xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 46f64e70)
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  *
99b760fd8SDouglas Gilbert  * Copyright (C) 2001 - 2017 Douglas Gilbert
101da177e4SLinus Torvalds  *
11773642d9SDouglas Gilbert  * This program is free software; you can redistribute it and/or modify
12773642d9SDouglas Gilbert  * it under the terms of the GNU General Public License as published by
13773642d9SDouglas Gilbert  * the Free Software Foundation; either version 2, or (at your option)
14773642d9SDouglas Gilbert  * any later version.
151da177e4SLinus Torvalds  *
1678d4e5a0SDouglas Gilbert  *  For documentation see http://sg.danny.cz/sg/sdebug26.html
171da177e4SLinus Torvalds  *
181da177e4SLinus Torvalds  */
191da177e4SLinus Torvalds 
20c1287970STomas Winkler 
21c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
22c1287970STomas Winkler 
231da177e4SLinus Torvalds #include <linux/module.h>
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds #include <linux/kernel.h>
261da177e4SLinus Torvalds #include <linux/errno.h>
27b333a819SDouglas Gilbert #include <linux/jiffies.h>
285a0e3ad6STejun Heo #include <linux/slab.h>
291da177e4SLinus Torvalds #include <linux/types.h>
301da177e4SLinus Torvalds #include <linux/string.h>
311da177e4SLinus Torvalds #include <linux/genhd.h>
321da177e4SLinus Torvalds #include <linux/fs.h>
331da177e4SLinus Torvalds #include <linux/init.h>
341da177e4SLinus Torvalds #include <linux/proc_fs.h>
351da177e4SLinus Torvalds #include <linux/vmalloc.h>
361da177e4SLinus Torvalds #include <linux/moduleparam.h>
37852e034dSJens Axboe #include <linux/scatterlist.h>
381da177e4SLinus Torvalds #include <linux/blkdev.h>
39c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h>
40cbf67842SDouglas Gilbert #include <linux/spinlock.h>
41cbf67842SDouglas Gilbert #include <linux/interrupt.h>
42cbf67842SDouglas Gilbert #include <linux/atomic.h>
43cbf67842SDouglas Gilbert #include <linux/hrtimer.h>
4409ba24c1SDouglas Gilbert #include <linux/uuid.h>
456ebf105cSChristoph Hellwig #include <linux/t10-pi.h>
46c6a44287SMartin K. Petersen 
47c6a44287SMartin K. Petersen #include <net/checksum.h>
489ff26eefSFUJITA Tomonori 
4944d92694SMartin K. Petersen #include <asm/unaligned.h>
5044d92694SMartin K. Petersen 
519ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
529ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
539ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
541da177e4SLinus Torvalds #include <scsi/scsi_host.h>
551da177e4SLinus Torvalds #include <scsi/scsicam.h>
56a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
57cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h>
58395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
591da177e4SLinus Torvalds 
60c6a44287SMartin K. Petersen #include "sd.h"
611da177e4SLinus Torvalds #include "scsi_logging.h"
621da177e4SLinus Torvalds 
63773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */
649b760fd8SDouglas Gilbert #define SDEBUG_VERSION "0187"	/* format to fit INQUIRY revision field */
659b760fd8SDouglas Gilbert static const char *sdebug_version_date = "20171202";
66cbf67842SDouglas Gilbert 
67cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
681da177e4SLinus Torvalds 
696f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
70c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
71c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
72c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
731da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
74c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
751da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7622017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
771da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
78c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
79cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
80cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
8119c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
8219c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8322017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8422017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
85cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
86cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
87cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
8822017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9
891da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
906f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
91c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
92c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
9322017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d
94acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1	/* with TARGET_CHANGED_ASC */
95acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
961da177e4SLinus Torvalds 
976f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
986f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
996f3cbf55SDouglas Gilbert 
1001da177e4SLinus Torvalds /* Default values for driver parameters */
1011da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1021da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1031da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1041da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1051da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1061da177e4SLinus Torvalds  */
1075b94e232SMartin K. Petersen #define DEF_ATO 1
1089b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10
109c2206098SDouglas Gilbert #define DEF_JDELAY   1		/* if > 0 unit is a jiffy */
1101da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1115b94e232SMartin K. Petersen #define DEF_DIF 0
1125b94e232SMartin K. Petersen #define DEF_DIX 0
1135b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1141da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1155b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1165b94e232SMartin K. Petersen #define DEF_GUARD 0
117cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1185b94e232SMartin K. Petersen #define DEF_LBPU 0
1195b94e232SMartin K. Petersen #define DEF_LBPWS 0
1205b94e232SMartin K. Petersen #define DEF_LBPWS10 0
121be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1225b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
123cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1245b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1251da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1261da177e4SLinus Torvalds #define DEF_OPTS   0
12732c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1285b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
12986e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0
130b01f6f83SDouglas Gilbert #define DEF_PTYPE   TYPE_DISK
131d986788bSMartin Pitt #define DEF_REMOVABLE false
132760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
1335b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1345b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1355b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1366014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1376014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1385b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1395b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1405b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
141c2248fc9SDouglas Gilbert #define DEF_STRICT 0
142c4837394SDouglas Gilbert #define DEF_STATISTICS false
143c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1
14409ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0
145c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999
1461da177e4SLinus Torvalds 
147b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0
148b01f6f83SDouglas Gilbert 
149773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
150773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
151773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
152773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
153773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
154773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
155773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
156773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
157773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
158773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
159773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
160773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF		0x400
161773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF		0x800
162773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE		0x1000
163773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE		0x2000
164773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE		0x4000
1657ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY		0x8000
166773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
167773642d9SDouglas Gilbert 			      SDEBUG_OPT_RESET_NOISE)
168773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
169773642d9SDouglas Gilbert 				  SDEBUG_OPT_TRANSPORT_ERR | \
170773642d9SDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
1717ee6d1b4SBart Van Assche 				  SDEBUG_OPT_SHORT_TRANSFER | \
1727ee6d1b4SBart Van Assche 				  SDEBUG_OPT_HOST_BUSY)
1731da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
174fd32119bSDouglas Gilbert  *   - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
1751da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
176773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_RECOVERED_ERR is set.
1776f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
178773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_TRANSPORT_ERR is set.
1791da177e4SLinus Torvalds  *
1801da177e4SLinus Torvalds  * When "every_nth" < 0 then after "- every_nth" commands:
181fd32119bSDouglas Gilbert  *   - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
1821da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
183773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_RECOVERED_ERR is set.
1846f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
185773642d9SDouglas Gilbert  *     commands if _DEBUG_OPT_TRANSPORT_ERR is set.
186773642d9SDouglas Gilbert  * This will continue on every subsequent command until some other action
187773642d9SDouglas Gilbert  * occurs (e.g. the user * writing a new value (other than -1 or 1) to
188773642d9SDouglas Gilbert  * every_nth via sysfs).
1891da177e4SLinus Torvalds  */
1901da177e4SLinus Torvalds 
191cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
192cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
193cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
194cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
195cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
196cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1
197cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2
1980d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3
19919c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4
200acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5	/* simulate firmware change */
201acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
202acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7
203cbf67842SDouglas Gilbert 
204773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
2051da177e4SLinus Torvalds  * sector on read commands: */
2061da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
20732f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
2101da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
2111da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
2121da177e4SLinus Torvalds 
213c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
214c4837394SDouglas Gilbert  * (for response) per submit queue at one time. Can be reduced by max_queue
215c4837394SDouglas Gilbert  * option. Command responses are not queued when jdelay=0 and ndelay=0. The
216c4837394SDouglas Gilbert  * per-device DEF_CMD_PER_LUN can be changed via sysfs:
217c4837394SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
218c4837394SDouglas Gilbert  * but cannot exceed SDEBUG_CANQUEUE .
219c4837394SDouglas Gilbert  */
220c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS  3	/* a WORD is bits in a long */
221c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE  (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
222cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN  255
223cbf67842SDouglas Gilbert 
224fd32119bSDouglas Gilbert #define F_D_IN			1
225fd32119bSDouglas Gilbert #define F_D_OUT			2
226fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
227fd32119bSDouglas Gilbert #define F_D_UNKN		8
228fd32119bSDouglas Gilbert #define F_RL_WLUN_OK		0x10
229fd32119bSDouglas Gilbert #define F_SKIP_UA		0x20
230fd32119bSDouglas Gilbert #define F_DELAY_OVERR		0x40
231fd32119bSDouglas Gilbert #define F_SA_LOW		0x80	/* cdb byte 1, bits 4 to 0 */
232fd32119bSDouglas Gilbert #define F_SA_HIGH		0x100	/* as used by variable length cdbs */
233fd32119bSDouglas Gilbert #define F_INV_OP		0x200
234fd32119bSDouglas Gilbert #define F_FAKE_RW		0x400
235fd32119bSDouglas Gilbert #define F_M_ACCESS		0x800	/* media access */
236fd32119bSDouglas Gilbert 
237fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
23846f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
239fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
240fd32119bSDouglas Gilbert 
241fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4
242fd32119bSDouglas Gilbert 
243b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32
244fd32119bSDouglas Gilbert 
245fd32119bSDouglas Gilbert 
246fd32119bSDouglas Gilbert struct sdebug_dev_info {
247fd32119bSDouglas Gilbert 	struct list_head dev_list;
248fd32119bSDouglas Gilbert 	unsigned int channel;
249fd32119bSDouglas Gilbert 	unsigned int target;
250fd32119bSDouglas Gilbert 	u64 lun;
251bf476433SChristoph Hellwig 	uuid_t lu_name;
252fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
253fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
254fd32119bSDouglas Gilbert 	atomic_t num_in_q;
255c4837394SDouglas Gilbert 	atomic_t stopped;
256fd32119bSDouglas Gilbert 	bool used;
257fd32119bSDouglas Gilbert };
258fd32119bSDouglas Gilbert 
259fd32119bSDouglas Gilbert struct sdebug_host_info {
260fd32119bSDouglas Gilbert 	struct list_head host_list;
261fd32119bSDouglas Gilbert 	struct Scsi_Host *shost;
262fd32119bSDouglas Gilbert 	struct device dev;
263fd32119bSDouglas Gilbert 	struct list_head dev_info_list;
264fd32119bSDouglas Gilbert };
265fd32119bSDouglas Gilbert 
266fd32119bSDouglas Gilbert #define to_sdebug_host(d)	\
267fd32119bSDouglas Gilbert 	container_of(d, struct sdebug_host_info, dev)
268fd32119bSDouglas Gilbert 
269fd32119bSDouglas Gilbert struct sdebug_defer {
270fd32119bSDouglas Gilbert 	struct hrtimer hrt;
271fd32119bSDouglas Gilbert 	struct execute_work ew;
272c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
273c4837394SDouglas Gilbert 	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
274c4837394SDouglas Gilbert 	int issuing_cpu;
275fd32119bSDouglas Gilbert };
276fd32119bSDouglas Gilbert 
277fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
278c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
279c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
280c4837394SDouglas Gilbert 	 */
281fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
282fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
283c4837394SDouglas Gilbert 	unsigned int inj_recovered:1;
284c4837394SDouglas Gilbert 	unsigned int inj_transport:1;
285c4837394SDouglas Gilbert 	unsigned int inj_dif:1;
286c4837394SDouglas Gilbert 	unsigned int inj_dix:1;
287c4837394SDouglas Gilbert 	unsigned int inj_short:1;
2887ee6d1b4SBart Van Assche 	unsigned int inj_host_busy:1;
289fd32119bSDouglas Gilbert };
290fd32119bSDouglas Gilbert 
291c4837394SDouglas Gilbert struct sdebug_queue {
292c4837394SDouglas Gilbert 	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
293c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
294c4837394SDouglas Gilbert 	spinlock_t qc_lock;
295c4837394SDouglas Gilbert 	atomic_t blocked;	/* to temporarily stop more being queued */
296fd32119bSDouglas Gilbert };
297fd32119bSDouglas Gilbert 
298c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
299c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
300c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
301c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
302c4837394SDouglas Gilbert 
303fd32119bSDouglas Gilbert struct opcode_info_t {
304b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
305b01f6f83SDouglas Gilbert 				/* for terminating element */
306fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
307fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
308fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
309fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
310fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
3119a051019SDouglas Gilbert 	u8 len_mask[16];	/* len_mask[0]-->cdb_len, then mask for cdb */
3129a051019SDouglas Gilbert 				/* 1 to min(cdb_len, 15); ignore cdb[15...] */
313fd32119bSDouglas Gilbert };
314fd32119bSDouglas Gilbert 
315fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
316c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
317c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
318c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
319c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
320c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
321c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
322c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
323c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
324c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
325c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
326c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
327c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
328c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
32946f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_IN_16 = 12,	/* add ...SERV_ACT_IN_12 if needed */
33046f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT_16 = 13,	/* add ...SERV_ACT_OUT_12 if needed */
331c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
332c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
333c2248fc9SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* 10 only */
33446f64e70SDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,	/* READ(32), WRITE(32) */
335c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
336c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
337c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
338c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
339c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
340c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
341c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
342c2248fc9SDouglas Gilbert 	SDEB_I_XDWRITEREAD = 25,	/* 10 only */
343c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_BUFFER = 26,
344c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_SAME = 27,		/* 10, 16 */
345c2248fc9SDouglas Gilbert 	SDEB_I_SYNC_CACHE = 28,		/* 10 only */
346c2248fc9SDouglas Gilbert 	SDEB_I_COMP_WRITE = 29,
3479a051019SDouglas Gilbert 	SDEB_I_LAST_ELEMENT = 30,	/* keep this last (previous + 1) */
348c2248fc9SDouglas Gilbert };
349c2248fc9SDouglas Gilbert 
350c4837394SDouglas Gilbert 
351c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
352c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
353c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
354c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
355c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
356c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
357c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
358c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
359c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
360c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
361c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
362c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
363c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
364c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
365c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
366c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
367c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
368c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
369c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
370c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
371fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
372c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
373c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
374c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
375c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
376c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
377c2248fc9SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
378c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
37946f64e70SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
380c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
381c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
382c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
38346f64e70SDouglas Gilbert 	SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
38446f64e70SDouglas Gilbert 	     0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
385c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
386c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
387c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
388c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
389c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
390c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
391c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
392c2248fc9SDouglas Gilbert };
393c2248fc9SDouglas Gilbert 
394c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
395c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
396c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
397c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
398c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
399c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
400c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
401c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
402c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
403c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
404c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
405c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
406c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
407c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
40838d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
40938d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
410c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
411c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
412c2248fc9SDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
41338d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
414acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
415c2248fc9SDouglas Gilbert 
41646f64e70SDouglas Gilbert /*
41746f64e70SDouglas Gilbert  * The following are overflow arrays for cdbs that "hit" the same index in
41846f64e70SDouglas Gilbert  * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
41946f64e70SDouglas Gilbert  * should be placed in opcode_info_arr[], the others should be placed here.
42046f64e70SDouglas Gilbert  */
42146f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = {
422c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
423c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
424c2248fc9SDouglas Gilbert };
425c2248fc9SDouglas Gilbert 
42646f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = {
427c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
428c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
429c2248fc9SDouglas Gilbert };
430c2248fc9SDouglas Gilbert 
43146f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = {
43246f64e70SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
433b7e24581SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
434c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
43546f64e70SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
436c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
43746f64e70SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
438b7e24581SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
439c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
440c2248fc9SDouglas Gilbert };
441c2248fc9SDouglas Gilbert 
44246f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = {
44346f64e70SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
44446f64e70SDouglas Gilbert 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
44546f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
44646f64e70SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
44746f64e70SDouglas Gilbert 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
44846f64e70SDouglas Gilbert 		   0, 0, 0} },
44946f64e70SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
45046f64e70SDouglas Gilbert 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
45146f64e70SDouglas Gilbert 		   0xbf, 0xc7, 0, 0, 0, 0} },
452c2248fc9SDouglas Gilbert };
453c2248fc9SDouglas Gilbert 
45446f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = {
455c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
456c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
45746f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
458c2248fc9SDouglas Gilbert };
459c2248fc9SDouglas Gilbert 
46046f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
46146f64e70SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
462b7e24581SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
463c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
464c2248fc9SDouglas Gilbert };
465c2248fc9SDouglas Gilbert 
46646f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
46738d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
468c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
46946f64e70SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
47038d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
471c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
47246f64e70SDouglas Gilbert 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
473c2248fc9SDouglas Gilbert };
474c2248fc9SDouglas Gilbert 
47546f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = {
47646f64e70SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
477c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
47846f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
479c2248fc9SDouglas Gilbert };
480c2248fc9SDouglas Gilbert 
48146f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = {
482c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
483c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
484c2248fc9SDouglas Gilbert };
485c2248fc9SDouglas Gilbert 
48646f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = {
487c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
488c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
489c2248fc9SDouglas Gilbert };
490c2248fc9SDouglas Gilbert 
491c2248fc9SDouglas Gilbert 
492c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
493c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
494c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
495c2248fc9SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
496c2248fc9SDouglas Gilbert /* 0 */
49746f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
498c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
49946f64e70SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
500c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
501c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
502c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
50346f64e70SDouglas Gilbert 	     0, 0} },					/* REPORT LUNS */
504c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
505c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
506c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
507c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
50846f64e70SDouglas Gilbert /* 5 */
50946f64e70SDouglas Gilbert 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
51046f64e70SDouglas Gilbert 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
51146f64e70SDouglas Gilbert 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
51246f64e70SDouglas Gilbert 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
51346f64e70SDouglas Gilbert 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
51446f64e70SDouglas Gilbert 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
51546f64e70SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
516c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
517c2248fc9SDouglas Gilbert 	     0, 0, 0} },
51846f64e70SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
519c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
520c2248fc9SDouglas Gilbert 	     0, 0} },
52146f64e70SDouglas Gilbert 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
52246f64e70SDouglas Gilbert 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
52346f64e70SDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
524c2248fc9SDouglas Gilbert /* 10 */
52546f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
52646f64e70SDouglas Gilbert 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
52746f64e70SDouglas Gilbert 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
52846f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },		/* WRITE(16) */
529c2248fc9SDouglas Gilbert 	{0, 0x1b, 0, 0, resp_start_stop, NULL,		/* START STOP UNIT */
530c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
53146f64e70SDouglas Gilbert 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
53246f64e70SDouglas Gilbert 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
53346f64e70SDouglas Gilbert 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
53446f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
53546f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA_OUT(16) */
536c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
53746f64e70SDouglas Gilbert 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
53846f64e70SDouglas Gilbert 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
53946f64e70SDouglas Gilbert 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
54046f64e70SDouglas Gilbert 				0xff, 0, 0xc7, 0, 0, 0, 0} },
54146f64e70SDouglas Gilbert /* 15 */
542c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
543c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
54446f64e70SDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, NULL, NULL, /* VERIFY(10) */
545f7f9f26bSDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
546f7f9f26bSDouglas Gilbert 	     0, 0, 0, 0, 0, 0} },
54746f64e70SDouglas Gilbert 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
54846f64e70SDouglas Gilbert 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
54946f64e70SDouglas Gilbert 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
55046f64e70SDouglas Gilbert 	     0xff, 0xff} },
55146f64e70SDouglas Gilbert 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
55246f64e70SDouglas Gilbert 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
553c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
554c2248fc9SDouglas Gilbert 	     0} },
55546f64e70SDouglas Gilbert 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
55646f64e70SDouglas Gilbert 	    NULL, release_iarr, /* RELEASE(10) <no response function> */
557c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
558c2248fc9SDouglas Gilbert 	     0} },
559c2248fc9SDouglas Gilbert /* 20 */
560f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
561f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
562c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
563c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
564c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
565c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
566c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
567c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
56846f64e70SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
569b7e24581SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
57046f64e70SDouglas Gilbert /* 25 */
57146f64e70SDouglas Gilbert 	{0, 0x53, 0, F_D_IN | F_D_OUT | FF_MEDIA_IO, resp_xdwriteread_10,
572b7e24581SDouglas Gilbert 	    NULL, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
57346f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },		/* XDWRITEREAD(10) */
574acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
575acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
576acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
57746f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
57846f64e70SDouglas Gilbert 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
57946f64e70SDouglas Gilbert 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
58046f64e70SDouglas Gilbert 		 0, 0, 0, 0, 0} },
58146f64e70SDouglas Gilbert 	{0, 0x35, 0, F_DELAY_OVERR | FF_MEDIA_IO, NULL, NULL, /* SYNC_CACHE */
582b7e24581SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
583c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
58446f64e70SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
585c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
586b7e24581SDouglas Gilbert 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
587c2248fc9SDouglas Gilbert 
588c2248fc9SDouglas Gilbert /* 30 */
589c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
590c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
591c2248fc9SDouglas Gilbert };
592c2248fc9SDouglas Gilbert 
593773642d9SDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;
594773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
5959b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
596c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
597773642d9SDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
598773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
599773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
600773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
601773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
602773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
603773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
604773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
605773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
606c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
607cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
608c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
609773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
610773642d9SDouglas Gilbert static int sdebug_no_uld;
611773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
612773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
613773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
614773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
615773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
61686e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
617b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
618773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
619773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
620773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
621773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
622773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
623773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
624773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
625773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
626773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
627773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
628773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
629773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
630773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
63109ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
632773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
633773642d9SDouglas Gilbert static bool sdebug_clustering;
634773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
635773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
636817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
637773642d9SDouglas Gilbert static bool sdebug_verbose;
638f46eb0e9SDouglas Gilbert static bool have_dif_prot;
639c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
640c4837394SDouglas Gilbert static bool sdebug_mq_active;
6411da177e4SLinus Torvalds 
642c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
6431da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
6441da177e4SLinus Torvalds 
6451da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
6461da177e4SLinus Torvalds    may still need them */
6471da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
6481da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
6491da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
6501da177e4SLinus Torvalds 
6511da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
6521da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
6531da177e4SLinus Torvalds 
6541da177e4SLinus Torvalds static unsigned char *fake_storep;	/* ramdisk storage */
6556ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_storep;	/* protection info */
65644d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
6571da177e4SLinus Torvalds 
65844d92694SMartin K. Petersen static unsigned long map_size;
659cbf67842SDouglas Gilbert static int num_aborts;
660cbf67842SDouglas Gilbert static int num_dev_resets;
661cbf67842SDouglas Gilbert static int num_target_resets;
662cbf67842SDouglas Gilbert static int num_bus_resets;
663cbf67842SDouglas Gilbert static int num_host_resets;
664c6a44287SMartin K. Petersen static int dix_writes;
665c6a44287SMartin K. Petersen static int dix_reads;
666c6a44287SMartin K. Petersen static int dif_errors;
6671da177e4SLinus Torvalds 
668c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
669c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
670fd32119bSDouglas Gilbert 
6711da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
6721da177e4SLinus Torvalds 
673cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
674cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
6751da177e4SLinus Torvalds 
6761da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
6771da177e4SLinus Torvalds 
6781da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
6791da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
6801da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
6811da177e4SLinus Torvalds };
6821da177e4SLinus Torvalds 
6831da177e4SLinus Torvalds static const int check_condition_result =
6841da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
6851da177e4SLinus Torvalds 
686c6a44287SMartin K. Petersen static const int illegal_condition_result =
687c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
688c6a44287SMartin K. Petersen 
689cbf67842SDouglas Gilbert static const int device_qfull_result =
690cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
691cbf67842SDouglas Gilbert 
692fd32119bSDouglas Gilbert 
693760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
694760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
695760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
696760f3b03SDouglas Gilbert  */
697760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
698fd32119bSDouglas Gilbert {
699fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
700fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
701fd32119bSDouglas Gilbert }
702c65b1445SDouglas Gilbert 
70314faa944SAkinobu Mita static void *fake_store(unsigned long long lba)
70414faa944SAkinobu Mita {
70514faa944SAkinobu Mita 	lba = do_div(lba, sdebug_store_sectors);
70614faa944SAkinobu Mita 
707773642d9SDouglas Gilbert 	return fake_storep + lba * sdebug_sector_size;
70814faa944SAkinobu Mita }
70914faa944SAkinobu Mita 
7106ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_store(sector_t sector)
71114faa944SAkinobu Mita {
71249413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
71314faa944SAkinobu Mita 
71414faa944SAkinobu Mita 	return dif_storep + sector;
71514faa944SAkinobu Mita }
71614faa944SAkinobu Mita 
7178dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
7188dea0d02SFUJITA Tomonori {
7198dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
7208dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
7218dea0d02SFUJITA Tomonori 
7228dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
7238dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
7248dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
7258dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
726773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
727773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
7288dea0d02SFUJITA Tomonori 		else
729773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
730773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
731f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
7328dea0d02SFUJITA Tomonori 	}
7338dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
7348dea0d02SFUJITA Tomonori }
7358dea0d02SFUJITA Tomonori 
73622017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
73722017ed2SDouglas Gilbert 
73822017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
739fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
740fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
74122017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
74222017ed2SDouglas Gilbert {
74322017ed2SDouglas Gilbert 	unsigned char *sbuff;
74422017ed2SDouglas Gilbert 	u8 sks[4];
74522017ed2SDouglas Gilbert 	int sl, asc;
74622017ed2SDouglas Gilbert 
74722017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
74822017ed2SDouglas Gilbert 	if (!sbuff) {
74922017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
75022017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
75122017ed2SDouglas Gilbert 		return;
75222017ed2SDouglas Gilbert 	}
75322017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
75422017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
755773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
75622017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
75722017ed2SDouglas Gilbert 	sks[0] = 0x80;
75822017ed2SDouglas Gilbert 	if (c_d)
75922017ed2SDouglas Gilbert 		sks[0] |= 0x40;
76022017ed2SDouglas Gilbert 	if (in_bit >= 0) {
76122017ed2SDouglas Gilbert 		sks[0] |= 0x8;
76222017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
76322017ed2SDouglas Gilbert 	}
76422017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
765773642d9SDouglas Gilbert 	if (sdebug_dsense) {
76622017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
76722017ed2SDouglas Gilbert 		sbuff[7] = sl;
76822017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
76922017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
77022017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
77122017ed2SDouglas Gilbert 	} else
77222017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
773773642d9SDouglas Gilbert 	if (sdebug_verbose)
77422017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
77522017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
77622017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
77722017ed2SDouglas Gilbert }
77822017ed2SDouglas Gilbert 
779cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
7808dea0d02SFUJITA Tomonori {
7818dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
7828dea0d02SFUJITA Tomonori 
783cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
784cbf67842SDouglas Gilbert 	if (!sbuff) {
785cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
786cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
787cbf67842SDouglas Gilbert 		return;
788cbf67842SDouglas Gilbert 	}
789cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
7908dea0d02SFUJITA Tomonori 
791773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
7928dea0d02SFUJITA Tomonori 
793773642d9SDouglas Gilbert 	if (sdebug_verbose)
794cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
795cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
796cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
7978dea0d02SFUJITA Tomonori }
7981da177e4SLinus Torvalds 
799fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
80022017ed2SDouglas Gilbert {
80122017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
80222017ed2SDouglas Gilbert }
80322017ed2SDouglas Gilbert 
8041da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
8051da177e4SLinus Torvalds {
806773642d9SDouglas Gilbert 	if (sdebug_verbose) {
807cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
808cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
809cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
810cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
811cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
812cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
813cbf67842SDouglas Gilbert 				    __func__);
814cbf67842SDouglas Gilbert 		else
815cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
816cbf67842SDouglas Gilbert 				    __func__, cmd);
8171da177e4SLinus Torvalds 	}
8181da177e4SLinus Torvalds 	return -EINVAL;
8191da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
8201da177e4SLinus Torvalds }
8211da177e4SLinus Torvalds 
8229b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
8239b760fd8SDouglas Gilbert {
8249b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
8259b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
8269b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8279b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8289b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8299b760fd8SDouglas Gilbert 		break;
8309b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
8319b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8329b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8339b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8349b760fd8SDouglas Gilbert 		break;
8359b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
8369b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8379b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8389b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8399b760fd8SDouglas Gilbert 		break;
8409b760fd8SDouglas Gilbert 	case 16:
8419b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8429b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
8439b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8449b760fd8SDouglas Gilbert 		break;
8459b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
8469b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8479b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
8489b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8499b760fd8SDouglas Gilbert 		break;
8509b760fd8SDouglas Gilbert 	default:
8519b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
8529b760fd8SDouglas Gilbert 			sdebug_cdb_len);
8539b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8549b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8559b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8569b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
8579b760fd8SDouglas Gilbert 		break;
8589b760fd8SDouglas Gilbert 	}
8599b760fd8SDouglas Gilbert }
8609b760fd8SDouglas Gilbert 
8619b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
8629b760fd8SDouglas Gilbert {
8639b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
8649b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
8659b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
8669b760fd8SDouglas Gilbert 
8679b760fd8SDouglas Gilbert 	spin_lock(&sdebug_host_list_lock);
8689b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
8699b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
8709b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
8719b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
8729b760fd8SDouglas Gilbert 		}
8739b760fd8SDouglas Gilbert 	}
8749b760fd8SDouglas Gilbert 	spin_unlock(&sdebug_host_list_lock);
8759b760fd8SDouglas Gilbert }
8769b760fd8SDouglas Gilbert 
87719c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
87819c8ead7SEwan D. Milne {
87919c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
88019c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
88119c8ead7SEwan D. Milne 
88219c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
88319c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
88419c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
88519c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
88619c8ead7SEwan D. Milne 			    (devip->target == dp->target))
88719c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
88819c8ead7SEwan D. Milne 		}
88919c8ead7SEwan D. Milne 	}
89019c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
89119c8ead7SEwan D. Milne }
89219c8ead7SEwan D. Milne 
893f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
8941da177e4SLinus Torvalds {
895cbf67842SDouglas Gilbert 	int k;
896cbf67842SDouglas Gilbert 
897cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
898cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
899cbf67842SDouglas Gilbert 		const char *cp = NULL;
900cbf67842SDouglas Gilbert 
901cbf67842SDouglas Gilbert 		switch (k) {
902cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
903f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
904f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
905773642d9SDouglas Gilbert 			if (sdebug_verbose)
906cbf67842SDouglas Gilbert 				cp = "power on reset";
907cbf67842SDouglas Gilbert 			break;
908cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
909f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
910f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
911773642d9SDouglas Gilbert 			if (sdebug_verbose)
912cbf67842SDouglas Gilbert 				cp = "bus reset";
913cbf67842SDouglas Gilbert 			break;
914cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
915f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
916f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
917773642d9SDouglas Gilbert 			if (sdebug_verbose)
918cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
919cbf67842SDouglas Gilbert 			break;
9200d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
921f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
922f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
923773642d9SDouglas Gilbert 			if (sdebug_verbose)
9240d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
925f49accf1SEwan D. Milne 			break;
926acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
927f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
928b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
929b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
930773642d9SDouglas Gilbert 			if (sdebug_verbose)
931acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
932acafd0b9SEwan D. Milne 			break;
933acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
934f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
935acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
936acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
937773642d9SDouglas Gilbert 			if (sdebug_verbose)
938acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
939acafd0b9SEwan D. Milne 			break;
94019c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
94119c8ead7SEwan D. Milne 			/*
94219c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
94319c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
94419c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
94519c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
946773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
94719c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
94819c8ead7SEwan D. Milne 			 */
949773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
95019c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
951f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
95219c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
95319c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
954773642d9SDouglas Gilbert 			if (sdebug_verbose)
95519c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
95619c8ead7SEwan D. Milne 			break;
957cbf67842SDouglas Gilbert 		default:
958773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
959773642d9SDouglas Gilbert 			if (sdebug_verbose)
960cbf67842SDouglas Gilbert 				cp = "unknown";
961cbf67842SDouglas Gilbert 			break;
962cbf67842SDouglas Gilbert 		}
963cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
964773642d9SDouglas Gilbert 		if (sdebug_verbose)
965f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
966cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
967cbf67842SDouglas Gilbert 				   my_name, cp);
9681da177e4SLinus Torvalds 		return check_condition_result;
9691da177e4SLinus Torvalds 	}
9701da177e4SLinus Torvalds 	return 0;
9711da177e4SLinus Torvalds }
9721da177e4SLinus Torvalds 
973fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
9741da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
9751da177e4SLinus Torvalds 				int arr_len)
9761da177e4SLinus Torvalds {
97721a61829SFUJITA Tomonori 	int act_len;
978072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
9791da177e4SLinus Torvalds 
980072d0bb3SFUJITA Tomonori 	if (!sdb->length)
9811da177e4SLinus Torvalds 		return 0;
982072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
983773642d9SDouglas Gilbert 		return DID_ERROR << 16;
98421a61829SFUJITA Tomonori 
98521a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
98621a61829SFUJITA Tomonori 				      arr, arr_len);
98721a61829SFUJITA Tomonori 	sdb->resid = scsi_bufflen(scp) - act_len;
98821a61829SFUJITA Tomonori 
9891da177e4SLinus Torvalds 	return 0;
9901da177e4SLinus Torvalds }
9911da177e4SLinus Torvalds 
992fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
993fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
994fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
995fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
996fb0cc8d1SDouglas Gilbert  */
997fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
998fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
999fb0cc8d1SDouglas Gilbert {
1000fb0cc8d1SDouglas Gilbert 	int act_len, n;
1001fb0cc8d1SDouglas Gilbert 	struct scsi_data_buffer *sdb = scsi_in(scp);
1002fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
1003fb0cc8d1SDouglas Gilbert 
1004fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
1005fb0cc8d1SDouglas Gilbert 		return 0;
1006fb0cc8d1SDouglas Gilbert 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
1007fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
1008fb0cc8d1SDouglas Gilbert 
1009fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1010fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
1011fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
1012fb0cc8d1SDouglas Gilbert 		 __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid);
1013fb0cc8d1SDouglas Gilbert 	n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
1014fb0cc8d1SDouglas Gilbert 	sdb->resid = min(sdb->resid, n);
1015fb0cc8d1SDouglas Gilbert 	return 0;
1016fb0cc8d1SDouglas Gilbert }
1017fb0cc8d1SDouglas Gilbert 
1018fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1019fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1020fb0cc8d1SDouglas Gilbert  */
10211da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
102221a61829SFUJITA Tomonori 			       int arr_len)
10231da177e4SLinus Torvalds {
102421a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
10251da177e4SLinus Torvalds 		return 0;
1026072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
10271da177e4SLinus Torvalds 		return -1;
102821a61829SFUJITA Tomonori 
102921a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
10301da177e4SLinus Torvalds }
10311da177e4SLinus Torvalds 
10321da177e4SLinus Torvalds 
1033e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1034e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
10359b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
10361b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
10371b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
10381b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
10391b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
10401da177e4SLinus Torvalds 
1041cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
1042760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
10435a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
104409ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1045bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
10461da177e4SLinus Torvalds {
1047c65b1445SDouglas Gilbert 	int num, port_a;
1048c65b1445SDouglas Gilbert 	char b[32];
10491da177e4SLinus Torvalds 
1050c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
10511da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
10521da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
10531da177e4SLinus Torvalds 	arr[1] = 0x1;
10541da177e4SLinus Torvalds 	arr[2] = 0x0;
1055e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1056e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
10571da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
10581da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
10591da177e4SLinus Torvalds 	arr[3] = num;
10601da177e4SLinus Torvalds 	num += 4;
1061c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
106209ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
106309ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
106409ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
106509ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
106609ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
106709ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
106809ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
106909ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
107009ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
107109ba24c1SDouglas Gilbert 			num += 16;
107209ba24c1SDouglas Gilbert 		} else {
10731b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1074c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1075c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1076c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1077c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
10781b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1079773642d9SDouglas Gilbert 			num += 8;
108009ba24c1SDouglas Gilbert 		}
1081c65b1445SDouglas Gilbert 		/* Target relative port number */
1082c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1083c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1084c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1085c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1086c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1087c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1088c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1089c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1090c65b1445SDouglas Gilbert 	}
10911b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1092c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1093c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1094c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1095c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
10961b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1097773642d9SDouglas Gilbert 	num += 8;
10981b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
10995a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
11005a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
11015a09e398SHannes Reinecke 	arr[num++] = 0x0;
11025a09e398SHannes Reinecke 	arr[num++] = 0x4;
11035a09e398SHannes Reinecke 	arr[num++] = 0;
11045a09e398SHannes Reinecke 	arr[num++] = 0;
1105773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1106773642d9SDouglas Gilbert 	num += 2;
11071b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1108c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1109c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1110c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1111c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
11121b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1113773642d9SDouglas Gilbert 	num += 8;
1114c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1115c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1116c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1117c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1118c65b1445SDouglas Gilbert 	arr[num++] = 24;
11191b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1120c65b1445SDouglas Gilbert 	num += 12;
1121c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1122c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1123c65b1445SDouglas Gilbert 	num += 8;
1124c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1125c65b1445SDouglas Gilbert 	num += 4;
1126c65b1445SDouglas Gilbert 	return num;
1127c65b1445SDouglas Gilbert }
1128c65b1445SDouglas Gilbert 
1129c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1130c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1131c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1132c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1133c65b1445SDouglas Gilbert };
1134c65b1445SDouglas Gilbert 
1135cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1136760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1137c65b1445SDouglas Gilbert {
1138c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1139c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1140c65b1445SDouglas Gilbert }
1141c65b1445SDouglas Gilbert 
1142cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1143760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1144c65b1445SDouglas Gilbert {
1145c65b1445SDouglas Gilbert 	int num = 0;
1146c65b1445SDouglas Gilbert 	const char * na1 = "https://www.kernel.org/config";
1147c65b1445SDouglas Gilbert 	const char * na2 = "http://www.kernel.org/log";
1148c65b1445SDouglas Gilbert 	int plen, olen;
1149c65b1445SDouglas Gilbert 
1150c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1151c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1152c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1153c65b1445SDouglas Gilbert 	olen = strlen(na1);
1154c65b1445SDouglas Gilbert 	plen = olen + 1;
1155c65b1445SDouglas Gilbert 	if (plen % 4)
1156c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1157c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1158c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1159c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1160c65b1445SDouglas Gilbert 	num += plen;
1161c65b1445SDouglas Gilbert 
1162c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1163c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1164c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1165c65b1445SDouglas Gilbert 	olen = strlen(na2);
1166c65b1445SDouglas Gilbert 	plen = olen + 1;
1167c65b1445SDouglas Gilbert 	if (plen % 4)
1168c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1169c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1170c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1171c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1172c65b1445SDouglas Gilbert 	num += plen;
1173c65b1445SDouglas Gilbert 
1174c65b1445SDouglas Gilbert 	return num;
1175c65b1445SDouglas Gilbert }
1176c65b1445SDouglas Gilbert 
1177c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1178760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1179c65b1445SDouglas Gilbert {
1180c65b1445SDouglas Gilbert 	int num = 0;
1181c65b1445SDouglas Gilbert 	int port_a, port_b;
1182c65b1445SDouglas Gilbert 
1183c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1184c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1185c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1186c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1187c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1188c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1189c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1190c65b1445SDouglas Gilbert 	num += 6;
1191c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1192c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1193c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1194c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1195c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1196c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1197c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
11981b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1199773642d9SDouglas Gilbert 	num += 8;
1200c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1201c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1202c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1203c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1204c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1205c65b1445SDouglas Gilbert 	num += 6;
1206c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1207c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1208c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1209c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1210c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1211c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1212c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
12131b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1214773642d9SDouglas Gilbert 	num += 8;
1215c65b1445SDouglas Gilbert 
1216c65b1445SDouglas Gilbert 	return num;
1217c65b1445SDouglas Gilbert }
1218c65b1445SDouglas Gilbert 
1219c65b1445SDouglas Gilbert 
1220c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1221c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1222c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1223c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1224c65b1445SDouglas Gilbert '1','2','3','4',
1225c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1226c65b1445SDouglas Gilbert 0xec,0,0,0,
1227c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1228c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1229c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1230c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1231c65b1445SDouglas Gilbert 0x53,0x41,
1232c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1233c65b1445SDouglas Gilbert 0x20,0x20,
1234c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1235c65b1445SDouglas Gilbert 0x10,0x80,
1236c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1237c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1238c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1239c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1240c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1241c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1242c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1243c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1244c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1245c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1246c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1247c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1248c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1249c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1250c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1251c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1252c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1253c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1254c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1255c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1256c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1257c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1258c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1259c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1260c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1261c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1262c65b1445SDouglas Gilbert };
1263c65b1445SDouglas Gilbert 
1264cbf67842SDouglas Gilbert /* ATA Information VPD page */
1265760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1266c65b1445SDouglas Gilbert {
1267c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1268c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1269c65b1445SDouglas Gilbert }
1270c65b1445SDouglas Gilbert 
1271c65b1445SDouglas Gilbert 
1272c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
12731e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
12741e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12751e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12761e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1277c65b1445SDouglas Gilbert };
1278c65b1445SDouglas Gilbert 
1279cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1280760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1281c65b1445SDouglas Gilbert {
1282ea61fca5SMartin K. Petersen 	unsigned int gran;
1283ea61fca5SMartin K. Petersen 
1284c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1285e308b3d1SMartin K. Petersen 
1286e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
128786e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
128886e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
128986e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
129086e6828aSLukas Herbolt 	else
1291773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1292773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1293e308b3d1SMartin K. Petersen 
1294e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1295773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1296773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
129744d92694SMartin K. Petersen 
1298e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1299773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1300e308b3d1SMartin K. Petersen 
1301773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1302e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1303773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1304e308b3d1SMartin K. Petersen 
1305e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1306773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
130744d92694SMartin K. Petersen 	}
130844d92694SMartin K. Petersen 
1309e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1310773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1311773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
131244d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
131344d92694SMartin K. Petersen 	}
131444d92694SMartin K. Petersen 
1315e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1316773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
13176014759cSMartin K. Petersen 
13185b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1319773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
13205b94e232SMartin K. Petersen 
13215b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
132244d92694SMartin K. Petersen 
1323c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
13241da177e4SLinus Torvalds }
13251da177e4SLinus Torvalds 
13261e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
1327760f3b03SDouglas Gilbert static int inquiry_vpd_b1(unsigned char *arr)
1328eac6e8e4SMatthew Wilcox {
1329eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1330eac6e8e4SMatthew Wilcox 	arr[0] = 0;
13311e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
13321e49f785SDouglas Gilbert 	arr[2] = 0;
13331e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
1334eac6e8e4SMatthew Wilcox 
1335eac6e8e4SMatthew Wilcox 	return 0x3c;
1336eac6e8e4SMatthew Wilcox }
13371da177e4SLinus Torvalds 
1338760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1339760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
13406014759cSMartin K. Petersen {
13413f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
13426014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1343773642d9SDouglas Gilbert 	if (sdebug_lbpu)
13446014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1345773642d9SDouglas Gilbert 	if (sdebug_lbpws)
13466014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1347773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
13485b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1349760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1350760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1351760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1352760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1353760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
13543f0bc3b3SMartin K. Petersen 	return 0x4;
13556014759cSMartin K. Petersen }
13566014759cSMartin K. Petersen 
13571da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1358c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
13591da177e4SLinus Torvalds 
1360c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
13611da177e4SLinus Torvalds {
13621da177e4SLinus Torvalds 	unsigned char pq_pdt;
13635a09e398SHannes Reinecke 	unsigned char * arr;
136401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
13655a09e398SHannes Reinecke 	int alloc_len, n, ret;
1366760f3b03SDouglas Gilbert 	bool have_wlun, is_disk;
13671da177e4SLinus Torvalds 
1368773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
13696f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
13706f3cbf55SDouglas Gilbert 	if (! arr)
13716f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1372760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
1373b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1374c2248fc9SDouglas Gilbert 	if (have_wlun)
1375b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1376b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1377b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1378c65b1445SDouglas Gilbert 	else
1379773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
13801da177e4SLinus Torvalds 	arr[0] = pq_pdt;
13811da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
138222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
13835a09e398SHannes Reinecke 		kfree(arr);
13841da177e4SLinus Torvalds 		return check_condition_result;
13851da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
13865a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1387c65b1445SDouglas Gilbert 		char lu_id_str[6];
1388c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
13891da177e4SLinus Torvalds 
13905a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
13915a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1392b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
139323183910SDouglas Gilbert 			host_no = 0;
1394c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1395c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1396c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1397c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1398c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
13991da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1400c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1401c65b1445SDouglas Gilbert 			n = 4;
1402c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1403c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1404c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1405c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1406c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1407c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1408c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1409c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1410760f3b03SDouglas Gilbert 			if (is_disk) {	  /* SBC only */
1411c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1412760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1413760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1414760f3b03SDouglas Gilbert 				arr[n++] = 0xb2;  /* Logical Block Prov */
1415760f3b03SDouglas Gilbert 			}
1416c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
14171da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1418c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
14191da177e4SLinus Torvalds 			arr[3] = len;
1420c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
14211da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1422c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1423760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
14245a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
142509ba24c1SDouglas Gilbert 						lu_id_str, len,
142609ba24c1SDouglas Gilbert 						&devip->lu_name);
1427c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1428c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1429760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1430c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1431c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1432760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1433c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1434c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1435c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
14368475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1437c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1438760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1439c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1440c6a44287SMartin K. Petersen 			else
1441c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1442c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1443c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1444c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1445c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1446c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1447c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1448c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1449c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1450c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1451c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1452760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1453760f3b03SDouglas Gilbert 		} else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
1454c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1455760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1456773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1457760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
1458c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1459760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1460760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
1461eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
1462760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b1(&arr[4]);
1463760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
14646014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1465760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
14661da177e4SLinus Torvalds 		} else {
146722017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
14685a09e398SHannes Reinecke 			kfree(arr);
14691da177e4SLinus Torvalds 			return check_condition_result;
14701da177e4SLinus Torvalds 		}
1471773642d9SDouglas Gilbert 		len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
14725a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1473c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
14745a09e398SHannes Reinecke 		kfree(arr);
14755a09e398SHannes Reinecke 		return ret;
14761da177e4SLinus Torvalds 	}
14771da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1478773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1479773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
14801da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
14811da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1482f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1483b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
148470bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1485c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
14861da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1487c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1488e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1489e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1490e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
14919b760fd8SDouglas Gilbert 	/* Use Vendor Specific area to place driver date in ASCII hex */
14929b760fd8SDouglas Gilbert 	memcpy(&arr[36], sdebug_version_date, 8);
14931da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1494760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1495760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1496c65b1445SDouglas Gilbert 	n = 62;
1497760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1498760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1499760f3b03SDouglas Gilbert 		n += 2;
1500760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1501760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1502760f3b03SDouglas Gilbert 		n += 2;
15031da177e4SLinus Torvalds 	}
1504760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
15055a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
15061da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
15075a09e398SHannes Reinecke 	kfree(arr);
15085a09e398SHannes Reinecke 	return ret;
15091da177e4SLinus Torvalds }
15101da177e4SLinus Torvalds 
1511fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1512fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1513fd32119bSDouglas Gilbert 
15141da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp,
15151da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip)
15161da177e4SLinus Torvalds {
15171da177e4SLinus Torvalds 	unsigned char * sbuff;
151801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1519cbf67842SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
15202492fc09STomas Winkler 	bool dsense;
15211da177e4SLinus Torvalds 	int len = 18;
15221da177e4SLinus Torvalds 
1523c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1524c2248fc9SDouglas Gilbert 	dsense = !!(cmd[1] & 1);
1525cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
1526c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1527c2248fc9SDouglas Gilbert 		if (dsense) {
1528c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1529c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1530c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
1531c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
1532c2248fc9SDouglas Gilbert 			len = 8;
1533c65b1445SDouglas Gilbert 		} else {
1534c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1535c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1536c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1537c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
1538c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
1539c65b1445SDouglas Gilbert 		}
1540c65b1445SDouglas Gilbert 	} else {
1541cbf67842SDouglas Gilbert 		memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
1542773642d9SDouglas Gilbert 		if (arr[0] >= 0x70 && dsense == sdebug_dsense)
1543c2248fc9SDouglas Gilbert 			;	/* have sense and formats match */
1544c2248fc9SDouglas Gilbert 		else if (arr[0] <= 0x70) {
1545c2248fc9SDouglas Gilbert 			if (dsense) {
1546c2248fc9SDouglas Gilbert 				memset(arr, 0, 8);
1547c2248fc9SDouglas Gilbert 				arr[0] = 0x72;
1548c2248fc9SDouglas Gilbert 				len = 8;
1549c2248fc9SDouglas Gilbert 			} else {
1550c2248fc9SDouglas Gilbert 				memset(arr, 0, 18);
1551c2248fc9SDouglas Gilbert 				arr[0] = 0x70;
1552c2248fc9SDouglas Gilbert 				arr[7] = 0xa;
1553c2248fc9SDouglas Gilbert 			}
1554c2248fc9SDouglas Gilbert 		} else if (dsense) {
1555c2248fc9SDouglas Gilbert 			memset(arr, 0, 8);
15561da177e4SLinus Torvalds 			arr[0] = 0x72;
15571da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
15581da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
15591da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
15601da177e4SLinus Torvalds 			len = 8;
1561c2248fc9SDouglas Gilbert 		} else {
1562c2248fc9SDouglas Gilbert 			memset(arr, 0, 18);
1563c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1564c2248fc9SDouglas Gilbert 			arr[2] = sbuff[1];
1565c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1566c2248fc9SDouglas Gilbert 			arr[12] = sbuff[1];
1567c2248fc9SDouglas Gilbert 			arr[13] = sbuff[3];
1568c65b1445SDouglas Gilbert 		}
1569c2248fc9SDouglas Gilbert 
1570c65b1445SDouglas Gilbert 	}
1571cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
15721da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
15731da177e4SLinus Torvalds }
15741da177e4SLinus Torvalds 
1575c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp,
1576c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
1577c65b1445SDouglas Gilbert {
157801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1579c4837394SDouglas Gilbert 	int power_cond, stop;
1580c65b1445SDouglas Gilbert 
1581c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1582c65b1445SDouglas Gilbert 	if (power_cond) {
158322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1584c65b1445SDouglas Gilbert 		return check_condition_result;
1585c65b1445SDouglas Gilbert 	}
1586c4837394SDouglas Gilbert 	stop = !(cmd[4] & 1);
1587c4837394SDouglas Gilbert 	atomic_xchg(&devip->stopped, stop);
1588c65b1445SDouglas Gilbert 	return 0;
1589c65b1445SDouglas Gilbert }
1590c65b1445SDouglas Gilbert 
159128898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
159228898873SFUJITA Tomonori {
1593773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1594773642d9SDouglas Gilbert 
1595773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1596773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1597773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
159828898873SFUJITA Tomonori 	else
159928898873SFUJITA Tomonori 		return sdebug_store_sectors;
160028898873SFUJITA Tomonori }
160128898873SFUJITA Tomonori 
16021da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
16031da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp,
16041da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
16051da177e4SLinus Torvalds {
16061da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1607c65b1445SDouglas Gilbert 	unsigned int capac;
16081da177e4SLinus Torvalds 
1609c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
161028898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
16111da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1612c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1613c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1614773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1615773642d9SDouglas Gilbert 	} else
1616773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1617773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
16181da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
16191da177e4SLinus Torvalds }
16201da177e4SLinus Torvalds 
1621c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1622c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp,
1623c65b1445SDouglas Gilbert 			  struct sdebug_dev_info * devip)
1624c65b1445SDouglas Gilbert {
162501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1626c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1627773642d9SDouglas Gilbert 	int alloc_len;
1628c65b1445SDouglas Gilbert 
1629773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1630c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
163128898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1632c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1633773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1634773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1635773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1636773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
163744d92694SMartin K. Petersen 
1638be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
16395b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1640760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1641760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1642760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1643760f3b03SDouglas Gilbert 		 */
1644760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1645760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1646be1dd78dSEric Sandeen 	}
164744d92694SMartin K. Petersen 
1648773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1649c6a44287SMartin K. Petersen 
1650760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1651773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1652c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1653c6a44287SMartin K. Petersen 	}
1654c6a44287SMartin K. Petersen 
1655c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1656c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1657c65b1445SDouglas Gilbert }
1658c65b1445SDouglas Gilbert 
16595a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
16605a09e398SHannes Reinecke 
16615a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp,
16625a09e398SHannes Reinecke 			      struct sdebug_dev_info * devip)
16635a09e398SHannes Reinecke {
166401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
16655a09e398SHannes Reinecke 	unsigned char * arr;
16665a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
16675a09e398SHannes Reinecke 	int n, ret, alen, rlen;
16685a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
16695a09e398SHannes Reinecke 
1670773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
16716f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
16726f3cbf55SDouglas Gilbert 	if (! arr)
16736f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
16745a09e398SHannes Reinecke 	/*
16755a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
16765a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
16775a09e398SHannes Reinecke 	 * So we create two port groups with one port each
16785a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
16795a09e398SHannes Reinecke 	 */
16805a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
16815a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
16825a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
16835a09e398SHannes Reinecke 			(devip->channel & 0x7f);
16845a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
16855a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
16865a09e398SHannes Reinecke 
16875a09e398SHannes Reinecke 	/*
16885a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
16895a09e398SHannes Reinecke 	 */
16905a09e398SHannes Reinecke 	n = 4;
1691b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
16925a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
16935a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
16945a09e398SHannes Reinecke 	} else {
16955a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1696773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
16975a09e398SHannes Reinecke 	}
1698773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1699773642d9SDouglas Gilbert 	n += 2;
17005a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17015a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
17025a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
17035a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
17045a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17055a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1706773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1707773642d9SDouglas Gilbert 	n += 2;
17085a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
17095a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1710773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1711773642d9SDouglas Gilbert 	n += 2;
17125a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17135a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
17145a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
17155a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
17165a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17175a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1718773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1719773642d9SDouglas Gilbert 	n += 2;
17205a09e398SHannes Reinecke 
17215a09e398SHannes Reinecke 	rlen = n - 4;
1722773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
17235a09e398SHannes Reinecke 
17245a09e398SHannes Reinecke 	/*
17255a09e398SHannes Reinecke 	 * Return the smallest value of either
17265a09e398SHannes Reinecke 	 * - The allocated length
17275a09e398SHannes Reinecke 	 * - The constructed command length
17285a09e398SHannes Reinecke 	 * - The maximum array size
17295a09e398SHannes Reinecke 	 */
17305a09e398SHannes Reinecke 	rlen = min(alen,n);
17315a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
17325a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
17335a09e398SHannes Reinecke 	kfree(arr);
17345a09e398SHannes Reinecke 	return ret;
17355a09e398SHannes Reinecke }
17365a09e398SHannes Reinecke 
1737fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1738fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
173938d5c833SDouglas Gilbert {
174038d5c833SDouglas Gilbert 	bool rctd;
174138d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
174238d5c833SDouglas Gilbert 	u16 req_sa, u;
174338d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
174438d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
174538d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
174638d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
174738d5c833SDouglas Gilbert 	u8 *arr;
174838d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
174938d5c833SDouglas Gilbert 
175038d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
175138d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
175238d5c833SDouglas Gilbert 	req_opcode = cmd[3];
175338d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
175438d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
17556d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
175638d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
175738d5c833SDouglas Gilbert 		return check_condition_result;
175838d5c833SDouglas Gilbert 	}
175938d5c833SDouglas Gilbert 	if (alloc_len > 8192)
176038d5c833SDouglas Gilbert 		a_len = 8192;
176138d5c833SDouglas Gilbert 	else
176238d5c833SDouglas Gilbert 		a_len = alloc_len;
176399531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
176438d5c833SDouglas Gilbert 	if (NULL == arr) {
176538d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
176638d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
176738d5c833SDouglas Gilbert 		return check_condition_result;
176838d5c833SDouglas Gilbert 	}
176938d5c833SDouglas Gilbert 	switch (reporting_opts) {
177038d5c833SDouglas Gilbert 	case 0:	/* all commands */
177138d5c833SDouglas Gilbert 		/* count number of commands */
177238d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
177338d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
177438d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
177538d5c833SDouglas Gilbert 				continue;
177638d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
177738d5c833SDouglas Gilbert 		}
177838d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
177938d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
178038d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
178138d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
178238d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
178338d5c833SDouglas Gilbert 				continue;
178438d5c833SDouglas Gilbert 			na = oip->num_attached;
178538d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
178638d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
178738d5c833SDouglas Gilbert 			if (rctd)
178838d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
178938d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
179038d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
179138d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
179238d5c833SDouglas Gilbert 			if (rctd)
179338d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
179438d5c833SDouglas Gilbert 			r_oip = oip;
179538d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
179638d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
179738d5c833SDouglas Gilbert 					continue;
179838d5c833SDouglas Gilbert 				offset += bump;
179938d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
180038d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
180138d5c833SDouglas Gilbert 				if (rctd)
180238d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
180338d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
180438d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
180538d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
180638d5c833SDouglas Gilbert 						   arr + offset + 6);
180738d5c833SDouglas Gilbert 				if (rctd)
180838d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
180938d5c833SDouglas Gilbert 							   arr + offset + 8);
181038d5c833SDouglas Gilbert 			}
181138d5c833SDouglas Gilbert 			oip = r_oip;
181238d5c833SDouglas Gilbert 			offset += bump;
181338d5c833SDouglas Gilbert 		}
181438d5c833SDouglas Gilbert 		break;
181538d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
181638d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
181738d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
181838d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
181938d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
182038d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
182138d5c833SDouglas Gilbert 			supp = 1;
182238d5c833SDouglas Gilbert 			offset = 4;
182338d5c833SDouglas Gilbert 		} else {
182438d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
182538d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
182638d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
182738d5c833SDouglas Gilbert 							     2, 2);
182838d5c833SDouglas Gilbert 					kfree(arr);
182938d5c833SDouglas Gilbert 					return check_condition_result;
183038d5c833SDouglas Gilbert 				}
183138d5c833SDouglas Gilbert 				req_sa = 0;
183238d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
183338d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
183438d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
183538d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
183638d5c833SDouglas Gilbert 				return check_condition_result;
183738d5c833SDouglas Gilbert 			}
183838d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
183938d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
184038d5c833SDouglas Gilbert 				supp = 3;
184138d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
184238d5c833SDouglas Gilbert 				na = oip->num_attached;
184338d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
184438d5c833SDouglas Gilbert 				     ++k, ++oip) {
184538d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
184638d5c833SDouglas Gilbert 						break;
184738d5c833SDouglas Gilbert 				}
184838d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
184938d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
185038d5c833SDouglas Gilbert 				na = oip->num_attached;
185138d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
185238d5c833SDouglas Gilbert 				     ++k, ++oip) {
185338d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
185438d5c833SDouglas Gilbert 						break;
185538d5c833SDouglas Gilbert 				}
185638d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
185738d5c833SDouglas Gilbert 			} else
185838d5c833SDouglas Gilbert 				supp = 3;
185938d5c833SDouglas Gilbert 			if (3 == supp) {
186038d5c833SDouglas Gilbert 				u = oip->len_mask[0];
186138d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
186238d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
186338d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
186438d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
186538d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
186638d5c833SDouglas Gilbert 				offset = 4 + u;
186738d5c833SDouglas Gilbert 			} else
186838d5c833SDouglas Gilbert 				offset = 4;
186938d5c833SDouglas Gilbert 		}
187038d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
187138d5c833SDouglas Gilbert 		if (rctd) {
187238d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
187338d5c833SDouglas Gilbert 			offset += 12;
187438d5c833SDouglas Gilbert 		}
187538d5c833SDouglas Gilbert 		break;
187638d5c833SDouglas Gilbert 	default:
187738d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
187838d5c833SDouglas Gilbert 		kfree(arr);
187938d5c833SDouglas Gilbert 		return check_condition_result;
188038d5c833SDouglas Gilbert 	}
188138d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
188238d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
188338d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
188438d5c833SDouglas Gilbert 	kfree(arr);
188538d5c833SDouglas Gilbert 	return errsts;
188638d5c833SDouglas Gilbert }
188738d5c833SDouglas Gilbert 
1888fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1889fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
189038d5c833SDouglas Gilbert {
189138d5c833SDouglas Gilbert 	bool repd;
189238d5c833SDouglas Gilbert 	u32 alloc_len, len;
189338d5c833SDouglas Gilbert 	u8 arr[16];
189438d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
189538d5c833SDouglas Gilbert 
189638d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
189738d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
189838d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
189938d5c833SDouglas Gilbert 	if (alloc_len < 4) {
190038d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
190138d5c833SDouglas Gilbert 		return check_condition_result;
190238d5c833SDouglas Gilbert 	}
190338d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
190438d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
190538d5c833SDouglas Gilbert 	if (repd) {
190638d5c833SDouglas Gilbert 		arr[3] = 0xc;
190738d5c833SDouglas Gilbert 		len = 16;
190838d5c833SDouglas Gilbert 	} else
190938d5c833SDouglas Gilbert 		len = 4;
191038d5c833SDouglas Gilbert 
191138d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
191238d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
191338d5c833SDouglas Gilbert }
191438d5c833SDouglas Gilbert 
19151da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
19161da177e4SLinus Torvalds 
19171da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
19181da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
19191da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
19201da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
19211da177e4SLinus Torvalds 
19221da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
19231da177e4SLinus Torvalds 	if (1 == pcontrol)
19241da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
19251da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
19261da177e4SLinus Torvalds }
19271da177e4SLinus Torvalds 
19281da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
19291da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
19301da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
19311da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
19321da177e4SLinus Torvalds 
19331da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
19341da177e4SLinus Torvalds 	if (1 == pcontrol)
19351da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
19361da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
19371da177e4SLinus Torvalds }
19381da177e4SLinus Torvalds 
19391da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target)
19401da177e4SLinus Torvalds {       /* Format device page for mode_sense */
19411da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
19421da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
19431da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
19441da177e4SLinus Torvalds 
19451da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
1946773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
1947773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
1948773642d9SDouglas Gilbert 	if (sdebug_removable)
19491da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
19501da177e4SLinus Torvalds 	if (1 == pcontrol)
19511da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
19521da177e4SLinus Torvalds 	return sizeof(format_pg);
19531da177e4SLinus Torvalds }
19541da177e4SLinus Torvalds 
1955fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1956fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1957fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
1958fd32119bSDouglas Gilbert 
19591da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
19601da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
1961cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1962cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1963cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
19641da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
19651da177e4SLinus Torvalds 
1966773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
1967cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
19681da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
19691da177e4SLinus Torvalds 	if (1 == pcontrol)
1970cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1971cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
1972cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
19731da177e4SLinus Torvalds 	return sizeof(caching_pg);
19741da177e4SLinus Torvalds }
19751da177e4SLinus Torvalds 
1976fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
1977fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
1978fd32119bSDouglas Gilbert 
19791da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
19801da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
1981c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1982c65b1445SDouglas Gilbert 					0, 0, 0, 0};
1983c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
19841da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
19851da177e4SLinus Torvalds 
1986773642d9SDouglas Gilbert 	if (sdebug_dsense)
19871da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
1988c65b1445SDouglas Gilbert 	else
1989c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
1990c6a44287SMartin K. Petersen 
1991773642d9SDouglas Gilbert 	if (sdebug_ato)
1992c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1993c6a44287SMartin K. Petersen 
19941da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
19951da177e4SLinus Torvalds 	if (1 == pcontrol)
1996c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1997c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1998c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
19991da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
20001da177e4SLinus Torvalds }
20011da177e4SLinus Torvalds 
2002c65b1445SDouglas Gilbert 
20031da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
20041da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2005c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
20061da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2007c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2008c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2009c65b1445SDouglas Gilbert 
20101da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
20111da177e4SLinus Torvalds 	if (1 == pcontrol)
2012c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2013c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2014c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
20151da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
20161da177e4SLinus Torvalds }
20171da177e4SLinus Torvalds 
2018c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
2019c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2020c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2021c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2022c65b1445SDouglas Gilbert 
2023c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2024c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2025c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2026c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2027c65b1445SDouglas Gilbert }
2028c65b1445SDouglas Gilbert 
2029c65b1445SDouglas Gilbert 
2030c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
2031c65b1445SDouglas Gilbert 			      int target_dev_id)
2032c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2033c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2034c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2035773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2036773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2037c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2038c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2039c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2040c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2041773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2042773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2043c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2044c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2045c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2046c65b1445SDouglas Gilbert 		};
2047c65b1445SDouglas Gilbert 	int port_a, port_b;
2048c65b1445SDouglas Gilbert 
20491b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
20501b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
20511b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
20521b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2053c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2054c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2055c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2056773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2057773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2058c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2059c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2060c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2061c65b1445SDouglas Gilbert }
2062c65b1445SDouglas Gilbert 
2063c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
2064c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2065c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2066c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2067c65b1445SDouglas Gilbert 		};
2068c65b1445SDouglas Gilbert 
2069c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2070c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2071c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2072c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2073c65b1445SDouglas Gilbert }
2074c65b1445SDouglas Gilbert 
20751da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
20761da177e4SLinus Torvalds 
2077fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2078fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
20791da177e4SLinus Torvalds {
208023183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
20811da177e4SLinus Torvalds 	unsigned char dev_spec;
2082760f3b03SDouglas Gilbert 	int alloc_len, offset, len, target_dev_id;
2083c2248fc9SDouglas Gilbert 	int target = scp->device->id;
20841da177e4SLinus Torvalds 	unsigned char * ap;
20851da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
208601123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2087760f3b03SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, bad_pcode;
20881da177e4SLinus Torvalds 
2089760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
20901da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
20911da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
20921da177e4SLinus Torvalds 	subpcode = cmd[3];
20931da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2094760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2095760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
2096760f3b03SDouglas Gilbert 	if (is_disk && !dbd)
209723183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
209823183910SDouglas Gilbert 	else
209923183910SDouglas Gilbert 		bd_len = 0;
2100773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
21011da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
21021da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2103cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
21041da177e4SLinus Torvalds 		return check_condition_result;
21051da177e4SLinus Torvalds 	}
2106c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2107c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2108b01f6f83SDouglas Gilbert 	/* for disks set DPOFUA bit and clear write protect (WP) bit */
2109760f3b03SDouglas Gilbert 	if (is_disk)
2110b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
211123183910SDouglas Gilbert 	else
211223183910SDouglas Gilbert 		dev_spec = 0x0;
21131da177e4SLinus Torvalds 	if (msense_6) {
21141da177e4SLinus Torvalds 		arr[2] = dev_spec;
211523183910SDouglas Gilbert 		arr[3] = bd_len;
21161da177e4SLinus Torvalds 		offset = 4;
21171da177e4SLinus Torvalds 	} else {
21181da177e4SLinus Torvalds 		arr[3] = dev_spec;
211923183910SDouglas Gilbert 		if (16 == bd_len)
212023183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
212123183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
21221da177e4SLinus Torvalds 		offset = 8;
21231da177e4SLinus Torvalds 	}
21241da177e4SLinus Torvalds 	ap = arr + offset;
212528898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
212628898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
212728898873SFUJITA Tomonori 
212823183910SDouglas Gilbert 	if (8 == bd_len) {
2129773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2130773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2131773642d9SDouglas Gilbert 		else
2132773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2133773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
213423183910SDouglas Gilbert 		offset += bd_len;
213523183910SDouglas Gilbert 		ap = arr + offset;
213623183910SDouglas Gilbert 	} else if (16 == bd_len) {
2137773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2138773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
213923183910SDouglas Gilbert 		offset += bd_len;
214023183910SDouglas Gilbert 		ap = arr + offset;
214123183910SDouglas Gilbert 	}
21421da177e4SLinus Torvalds 
2143c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2144c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
214522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
21461da177e4SLinus Torvalds 		return check_condition_result;
21471da177e4SLinus Torvalds 	}
2148760f3b03SDouglas Gilbert 	bad_pcode = false;
2149760f3b03SDouglas Gilbert 
21501da177e4SLinus Torvalds 	switch (pcode) {
21511da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
21521da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
21531da177e4SLinus Torvalds 		offset += len;
21541da177e4SLinus Torvalds 		break;
21551da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
21561da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
21571da177e4SLinus Torvalds 		offset += len;
21581da177e4SLinus Torvalds 		break;
21591da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2160760f3b03SDouglas Gilbert 		if (is_disk) {
21611da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
21621da177e4SLinus Torvalds 			offset += len;
2163760f3b03SDouglas Gilbert 		} else
2164760f3b03SDouglas Gilbert 			bad_pcode = true;
21651da177e4SLinus Torvalds 		break;
21661da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2167760f3b03SDouglas Gilbert 		if (is_disk) {
21681da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
21691da177e4SLinus Torvalds 			offset += len;
2170760f3b03SDouglas Gilbert 		} else
2171760f3b03SDouglas Gilbert 			bad_pcode = true;
21721da177e4SLinus Torvalds 		break;
21731da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
21741da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
21751da177e4SLinus Torvalds 		offset += len;
21761da177e4SLinus Torvalds 		break;
2177c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2178c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
217922017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2180c65b1445SDouglas Gilbert 			return check_condition_result;
2181c65b1445SDouglas Gilbert 		}
2182c65b1445SDouglas Gilbert 		len = 0;
2183c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2184c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2185c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2186c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2187c65b1445SDouglas Gilbert 						  target_dev_id);
2188c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2189c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2190c65b1445SDouglas Gilbert 		offset += len;
2191c65b1445SDouglas Gilbert 		break;
21921da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
21931da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
21941da177e4SLinus Torvalds 		offset += len;
21951da177e4SLinus Torvalds 		break;
21961da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2197c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
21981da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
21991da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2200760f3b03SDouglas Gilbert 			if (is_disk) {
2201760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2202760f3b03SDouglas Gilbert 						      target);
2203760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2204760f3b03SDouglas Gilbert 						       target);
2205760f3b03SDouglas Gilbert 			}
22061da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2207c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2208c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2209c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2210c65b1445SDouglas Gilbert 						  target, target_dev_id);
2211c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2212c65b1445SDouglas Gilbert 			}
22131da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2214760f3b03SDouglas Gilbert 			offset += len;
2215c65b1445SDouglas Gilbert 		} else {
221622017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2217c65b1445SDouglas Gilbert 			return check_condition_result;
2218c65b1445SDouglas Gilbert 		}
22191da177e4SLinus Torvalds 		break;
22201da177e4SLinus Torvalds 	default:
2221760f3b03SDouglas Gilbert 		bad_pcode = true;
2222760f3b03SDouglas Gilbert 		break;
2223760f3b03SDouglas Gilbert 	}
2224760f3b03SDouglas Gilbert 	if (bad_pcode) {
222522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
22261da177e4SLinus Torvalds 		return check_condition_result;
22271da177e4SLinus Torvalds 	}
22281da177e4SLinus Torvalds 	if (msense_6)
22291da177e4SLinus Torvalds 		arr[0] = offset - 1;
2230773642d9SDouglas Gilbert 	else
2231773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
22321da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
22331da177e4SLinus Torvalds }
22341da177e4SLinus Torvalds 
2235c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2236c65b1445SDouglas Gilbert 
2237fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2238fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2239c65b1445SDouglas Gilbert {
2240c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2241c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2242c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
224301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2244c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2245c65b1445SDouglas Gilbert 
2246c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2247c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2248c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2249773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2250c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
225122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2252c65b1445SDouglas Gilbert 		return check_condition_result;
2253c65b1445SDouglas Gilbert 	}
2254c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2255c65b1445SDouglas Gilbert 	if (-1 == res)
2256773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2257773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2258cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2259cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2260cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2261773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2262773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
226323183910SDouglas Gilbert 	if (md_len > 2) {
226422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2265c65b1445SDouglas Gilbert 		return check_condition_result;
2266c65b1445SDouglas Gilbert 	}
2267c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2268c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2269c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2270c65b1445SDouglas Gilbert 	if (ps) {
227122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2272c65b1445SDouglas Gilbert 		return check_condition_result;
2273c65b1445SDouglas Gilbert 	}
2274c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2275773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2276c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2277c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2278cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2279c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2280c65b1445SDouglas Gilbert 		return check_condition_result;
2281c65b1445SDouglas Gilbert 	}
2282c65b1445SDouglas Gilbert 	switch (mpage) {
2283cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2284cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2285cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2286cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2287cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2288cbf67842SDouglas Gilbert 		}
2289cbf67842SDouglas Gilbert 		break;
2290c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2291c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2292c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2293c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
2294773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2295cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2296c65b1445SDouglas Gilbert 		}
2297c65b1445SDouglas Gilbert 		break;
2298c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2299c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2300c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2301c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2302cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2303c65b1445SDouglas Gilbert 		}
2304c65b1445SDouglas Gilbert 		break;
2305c65b1445SDouglas Gilbert 	default:
2306c65b1445SDouglas Gilbert 		break;
2307c65b1445SDouglas Gilbert 	}
230822017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2309c65b1445SDouglas Gilbert 	return check_condition_result;
2310cbf67842SDouglas Gilbert set_mode_changed_ua:
2311cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2312cbf67842SDouglas Gilbert 	return 0;
2313c65b1445SDouglas Gilbert }
2314c65b1445SDouglas Gilbert 
2315c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr)
2316c65b1445SDouglas Gilbert {
2317c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2318c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2319c65b1445SDouglas Gilbert 		};
2320c65b1445SDouglas Gilbert 
2321c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2322c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2323c65b1445SDouglas Gilbert }
2324c65b1445SDouglas Gilbert 
2325c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr)
2326c65b1445SDouglas Gilbert {
2327c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2328c65b1445SDouglas Gilbert 		};
2329c65b1445SDouglas Gilbert 
2330c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2331c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2332c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2333c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2334c65b1445SDouglas Gilbert 	}
2335c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2336c65b1445SDouglas Gilbert }
2337c65b1445SDouglas Gilbert 
2338c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2339c65b1445SDouglas Gilbert 
2340c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2341c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2342c65b1445SDouglas Gilbert {
2343ab17241cSBart Van Assche 	int ppc, sp, pcode, subpcode, alloc_len, len, n;
2344c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
234501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2346c65b1445SDouglas Gilbert 
2347c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2348c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2349c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2350c65b1445SDouglas Gilbert 	if (ppc || sp) {
235122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2352c65b1445SDouglas Gilbert 		return check_condition_result;
2353c65b1445SDouglas Gilbert 	}
2354c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
235523183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2356773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2357c65b1445SDouglas Gilbert 	arr[0] = pcode;
235823183910SDouglas Gilbert 	if (0 == subpcode) {
2359c65b1445SDouglas Gilbert 		switch (pcode) {
2360c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2361c65b1445SDouglas Gilbert 			n = 4;
2362c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2363c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2364c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2365c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2366c65b1445SDouglas Gilbert 			break;
2367c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2368c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2369c65b1445SDouglas Gilbert 			break;
2370c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2371c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2372c65b1445SDouglas Gilbert 			break;
2373c65b1445SDouglas Gilbert 		default:
237422017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2375c65b1445SDouglas Gilbert 			return check_condition_result;
2376c65b1445SDouglas Gilbert 		}
237723183910SDouglas Gilbert 	} else if (0xff == subpcode) {
237823183910SDouglas Gilbert 		arr[0] |= 0x40;
237923183910SDouglas Gilbert 		arr[1] = subpcode;
238023183910SDouglas Gilbert 		switch (pcode) {
238123183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
238223183910SDouglas Gilbert 			n = 4;
238323183910SDouglas Gilbert 			arr[n++] = 0x0;
238423183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
238523183910SDouglas Gilbert 			arr[n++] = 0x0;
238623183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
238723183910SDouglas Gilbert 			arr[n++] = 0xd;
238823183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
238923183910SDouglas Gilbert 			arr[n++] = 0x2f;
239023183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
239123183910SDouglas Gilbert 			arr[3] = n - 4;
239223183910SDouglas Gilbert 			break;
239323183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
239423183910SDouglas Gilbert 			n = 4;
239523183910SDouglas Gilbert 			arr[n++] = 0xd;
239623183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
239723183910SDouglas Gilbert 			arr[3] = n - 4;
239823183910SDouglas Gilbert 			break;
239923183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
240023183910SDouglas Gilbert 			n = 4;
240123183910SDouglas Gilbert 			arr[n++] = 0x2f;
240223183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
240323183910SDouglas Gilbert 			arr[3] = n - 4;
240423183910SDouglas Gilbert 			break;
240523183910SDouglas Gilbert 		default:
240622017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
240723183910SDouglas Gilbert 			return check_condition_result;
240823183910SDouglas Gilbert 		}
240923183910SDouglas Gilbert 	} else {
241022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
241123183910SDouglas Gilbert 		return check_condition_result;
241223183910SDouglas Gilbert 	}
2413773642d9SDouglas Gilbert 	len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
2414c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
2415c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
2416c65b1445SDouglas Gilbert }
2417c65b1445SDouglas Gilbert 
2418cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp,
241919789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
24201da177e4SLinus Torvalds {
2421c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
242222017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
24231da177e4SLinus Torvalds 		return check_condition_result;
24241da177e4SLinus Torvalds 	}
2425c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2426c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
242722017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2428cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2429c65b1445SDouglas Gilbert 		return check_condition_result;
2430c65b1445SDouglas Gilbert 	}
243119789100SFUJITA Tomonori 	return 0;
243219789100SFUJITA Tomonori }
243319789100SFUJITA Tomonori 
2434a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
24350a7e69c7SDouglas Gilbert static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
24360a7e69c7SDouglas Gilbert 			    u32 num, bool do_write)
243719789100SFUJITA Tomonori {
243819789100SFUJITA Tomonori 	int ret;
2439c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2440a4517511SAkinobu Mita 	struct scsi_data_buffer *sdb;
2441a4517511SAkinobu Mita 	enum dma_data_direction dir;
244219789100SFUJITA Tomonori 
2443c2248fc9SDouglas Gilbert 	if (do_write) {
2444a4517511SAkinobu Mita 		sdb = scsi_out(scmd);
2445a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
2446a4517511SAkinobu Mita 	} else {
2447a4517511SAkinobu Mita 		sdb = scsi_in(scmd);
2448a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2449a4517511SAkinobu Mita 	}
2450a4517511SAkinobu Mita 
2451a4517511SAkinobu Mita 	if (!sdb->length)
2452a4517511SAkinobu Mita 		return 0;
2453a4517511SAkinobu Mita 	if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2454a4517511SAkinobu Mita 		return -1;
245519789100SFUJITA Tomonori 
245619789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
245719789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
245819789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
245919789100SFUJITA Tomonori 
2460386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2461773642d9SDouglas Gilbert 		   fake_storep + (block * sdebug_sector_size),
24620a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
2463773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2464a4517511SAkinobu Mita 		return ret;
2465a4517511SAkinobu Mita 
2466a4517511SAkinobu Mita 	if (rest) {
2467386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2468773642d9SDouglas Gilbert 			    fake_storep, rest * sdebug_sector_size,
24690a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
24700a7e69c7SDouglas Gilbert 			    do_write);
2471a4517511SAkinobu Mita 	}
247219789100SFUJITA Tomonori 
247319789100SFUJITA Tomonori 	return ret;
247419789100SFUJITA Tomonori }
247519789100SFUJITA Tomonori 
247638d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of
247738d5c833SDouglas Gilbert  * arr into fake_store(lba,num) and return true. If comparison fails then
247838d5c833SDouglas Gilbert  * return false. */
2479fd32119bSDouglas Gilbert static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
248038d5c833SDouglas Gilbert {
248138d5c833SDouglas Gilbert 	bool res;
248238d5c833SDouglas Gilbert 	u64 block, rest = 0;
248338d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2484773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
248538d5c833SDouglas Gilbert 
248638d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
248738d5c833SDouglas Gilbert 	if (block + num > store_blks)
248838d5c833SDouglas Gilbert 		rest = block + num - store_blks;
248938d5c833SDouglas Gilbert 
249038d5c833SDouglas Gilbert 	res = !memcmp(fake_storep + (block * lb_size), arr,
249138d5c833SDouglas Gilbert 		      (num - rest) * lb_size);
249238d5c833SDouglas Gilbert 	if (!res)
249338d5c833SDouglas Gilbert 		return res;
249438d5c833SDouglas Gilbert 	if (rest)
249538d5c833SDouglas Gilbert 		res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
249638d5c833SDouglas Gilbert 			     rest * lb_size);
249738d5c833SDouglas Gilbert 	if (!res)
249838d5c833SDouglas Gilbert 		return res;
249938d5c833SDouglas Gilbert 	arr += num * lb_size;
250038d5c833SDouglas Gilbert 	memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
250138d5c833SDouglas Gilbert 	if (rest)
250238d5c833SDouglas Gilbert 		memcpy(fake_storep, arr + ((num - rest) * lb_size),
250338d5c833SDouglas Gilbert 		       rest * lb_size);
250438d5c833SDouglas Gilbert 	return res;
250538d5c833SDouglas Gilbert }
250638d5c833SDouglas Gilbert 
250751d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2508beb40ea4SAkinobu Mita {
250951d648afSAkinobu Mita 	__be16 csum;
2510beb40ea4SAkinobu Mita 
2511773642d9SDouglas Gilbert 	if (sdebug_guard)
251251d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
251351d648afSAkinobu Mita 	else
2514beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
251551d648afSAkinobu Mita 
2516beb40ea4SAkinobu Mita 	return csum;
2517beb40ea4SAkinobu Mita }
2518beb40ea4SAkinobu Mita 
25196ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
2520beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
2521beb40ea4SAkinobu Mita {
2522773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
2523beb40ea4SAkinobu Mita 
2524beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
2525c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
2526beb40ea4SAkinobu Mita 			(unsigned long)sector,
2527beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
2528beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
2529beb40ea4SAkinobu Mita 		return 0x01;
2530beb40ea4SAkinobu Mita 	}
25318475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
2532beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
2533c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2534c1287970STomas Winkler 			(unsigned long)sector);
2535beb40ea4SAkinobu Mita 		return 0x03;
2536beb40ea4SAkinobu Mita 	}
25378475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2538beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
2539c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2540c1287970STomas Winkler 			(unsigned long)sector);
2541beb40ea4SAkinobu Mita 		return 0x03;
2542beb40ea4SAkinobu Mita 	}
2543beb40ea4SAkinobu Mita 	return 0;
2544beb40ea4SAkinobu Mita }
2545beb40ea4SAkinobu Mita 
2546bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
254765f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
2548c6a44287SMartin K. Petersen {
2549be4e11beSAkinobu Mita 	size_t resid;
2550c6a44287SMartin K. Petersen 	void *paddr;
255114faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
2552be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
2553c6a44287SMartin K. Petersen 
2554e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
2555e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
2556c6a44287SMartin K. Petersen 
2557be4e11beSAkinobu Mita 	sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2558be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2559be4e11beSAkinobu Mita 			(read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2560be4e11beSAkinobu Mita 
2561be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
2562be4e11beSAkinobu Mita 		size_t len = min(miter.length, resid);
256314faa944SAkinobu Mita 		void *start = dif_store(sector);
2564be4e11beSAkinobu Mita 		size_t rest = 0;
256514faa944SAkinobu Mita 
256614faa944SAkinobu Mita 		if (dif_store_end < start + len)
256714faa944SAkinobu Mita 			rest = start + len - dif_store_end;
2568c6a44287SMartin K. Petersen 
2569be4e11beSAkinobu Mita 		paddr = miter.addr;
257014faa944SAkinobu Mita 
257165f72f2aSAkinobu Mita 		if (read)
257265f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
257365f72f2aSAkinobu Mita 		else
257465f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
257565f72f2aSAkinobu Mita 
257665f72f2aSAkinobu Mita 		if (rest) {
257765f72f2aSAkinobu Mita 			if (read)
257814faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
257965f72f2aSAkinobu Mita 			else
258065f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
258165f72f2aSAkinobu Mita 		}
2582c6a44287SMartin K. Petersen 
2583e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
2584c6a44287SMartin K. Petersen 		resid -= len;
2585c6a44287SMartin K. Petersen 	}
2586be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
2587bb8c063cSAkinobu Mita }
2588c6a44287SMartin K. Petersen 
2589bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2590bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
2591bb8c063cSAkinobu Mita {
2592bb8c063cSAkinobu Mita 	unsigned int i;
25936ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
2594bb8c063cSAkinobu Mita 	sector_t sector;
2595bb8c063cSAkinobu Mita 
2596c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
2597bb8c063cSAkinobu Mita 		int ret;
2598bb8c063cSAkinobu Mita 
2599bb8c063cSAkinobu Mita 		sector = start_sec + i;
2600bb8c063cSAkinobu Mita 		sdt = dif_store(sector);
2601bb8c063cSAkinobu Mita 
260251d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
2603bb8c063cSAkinobu Mita 			continue;
2604bb8c063cSAkinobu Mita 
2605bb8c063cSAkinobu Mita 		ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2606bb8c063cSAkinobu Mita 		if (ret) {
2607bb8c063cSAkinobu Mita 			dif_errors++;
2608bb8c063cSAkinobu Mita 			return ret;
2609bb8c063cSAkinobu Mita 		}
2610bb8c063cSAkinobu Mita 	}
2611bb8c063cSAkinobu Mita 
261265f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, true);
2613c6a44287SMartin K. Petersen 	dix_reads++;
2614c6a44287SMartin K. Petersen 
2615c6a44287SMartin K. Petersen 	return 0;
2616c6a44287SMartin K. Petersen }
2617c6a44287SMartin K. Petersen 
2618fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
261919789100SFUJITA Tomonori {
2620c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2621c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
2622c2248fc9SDouglas Gilbert 	u64 lba;
2623c2248fc9SDouglas Gilbert 	u32 num;
2624c2248fc9SDouglas Gilbert 	u32 ei_lba;
262519789100SFUJITA Tomonori 	unsigned long iflags;
262619789100SFUJITA Tomonori 	int ret;
2627c2248fc9SDouglas Gilbert 	bool check_prot;
262819789100SFUJITA Tomonori 
2629c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2630c2248fc9SDouglas Gilbert 	case READ_16:
2631c2248fc9SDouglas Gilbert 		ei_lba = 0;
2632c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2633c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2634c2248fc9SDouglas Gilbert 		check_prot = true;
2635c2248fc9SDouglas Gilbert 		break;
2636c2248fc9SDouglas Gilbert 	case READ_10:
2637c2248fc9SDouglas Gilbert 		ei_lba = 0;
2638c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2639c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2640c2248fc9SDouglas Gilbert 		check_prot = true;
2641c2248fc9SDouglas Gilbert 		break;
2642c2248fc9SDouglas Gilbert 	case READ_6:
2643c2248fc9SDouglas Gilbert 		ei_lba = 0;
2644c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2645c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2646c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2647c2248fc9SDouglas Gilbert 		check_prot = true;
2648c2248fc9SDouglas Gilbert 		break;
2649c2248fc9SDouglas Gilbert 	case READ_12:
2650c2248fc9SDouglas Gilbert 		ei_lba = 0;
2651c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2652c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2653c2248fc9SDouglas Gilbert 		check_prot = true;
2654c2248fc9SDouglas Gilbert 		break;
2655c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
2656c2248fc9SDouglas Gilbert 		ei_lba = 0;
2657c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2658c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2659c2248fc9SDouglas Gilbert 		check_prot = false;
2660c2248fc9SDouglas Gilbert 		break;
2661c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
2662c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2663c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2664c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2665c2248fc9SDouglas Gilbert 		check_prot = false;
2666c2248fc9SDouglas Gilbert 		break;
2667c2248fc9SDouglas Gilbert 	}
2668f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
26698475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2670c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2671c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2672c2248fc9SDouglas Gilbert 			return check_condition_result;
2673c2248fc9SDouglas Gilbert 		}
26748475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
26758475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
2676c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2677c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2678c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2679c2248fc9SDouglas Gilbert 	}
2680f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
2681c4837394SDouglas Gilbert 		sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
2682c2248fc9SDouglas Gilbert 
2683c4837394SDouglas Gilbert 		if (sqcp) {
2684c4837394SDouglas Gilbert 			if (sqcp->inj_short)
2685c2248fc9SDouglas Gilbert 				num /= 2;
2686c2248fc9SDouglas Gilbert 		}
2687c4837394SDouglas Gilbert 	} else
2688c4837394SDouglas Gilbert 		sqcp = NULL;
2689c2248fc9SDouglas Gilbert 
2690c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2691f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
2692c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2693c2248fc9SDouglas Gilbert 		return check_condition_result;
2694c2248fc9SDouglas Gilbert 	}
2695c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2696f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
2697c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2698c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2699c2248fc9SDouglas Gilbert 		return check_condition_result;
2700c2248fc9SDouglas Gilbert 	}
270119789100SFUJITA Tomonori 
2702f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
270332f7ef73SDouglas Gilbert 		     (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
2704f46eb0e9SDouglas Gilbert 		     ((lba + num) > OPT_MEDIUM_ERR_ADDR))) {
2705c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
2706c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
2707c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
2708c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2709c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
271032f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
271132f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
2712c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
2713c65b1445SDouglas Gilbert 		}
2714c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
27151da177e4SLinus Torvalds 		return check_condition_result;
27161da177e4SLinus Torvalds 	}
2717c6a44287SMartin K. Petersen 
27186c78cc06SAkinobu Mita 	read_lock_irqsave(&atomic_rw, iflags);
27196c78cc06SAkinobu Mita 
2720c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2721f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
2722c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
2723c6a44287SMartin K. Petersen 
2724c6a44287SMartin K. Petersen 		if (prot_ret) {
27256c78cc06SAkinobu Mita 			read_unlock_irqrestore(&atomic_rw, iflags);
2726c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
2727c6a44287SMartin K. Petersen 			return illegal_condition_result;
2728c6a44287SMartin K. Petersen 		}
2729c6a44287SMartin K. Petersen 	}
2730c6a44287SMartin K. Petersen 
27310a7e69c7SDouglas Gilbert 	ret = do_device_access(scp, 0, lba, num, false);
27321da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
2733f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
2734a4517511SAkinobu Mita 		return DID_ERROR << 16;
2735a4517511SAkinobu Mita 
2736c2248fc9SDouglas Gilbert 	scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
2737a4517511SAkinobu Mita 
2738c4837394SDouglas Gilbert 	if (unlikely(sqcp)) {
2739c4837394SDouglas Gilbert 		if (sqcp->inj_recovered) {
2740c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
2741c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
2742c2248fc9SDouglas Gilbert 			return check_condition_result;
2743c4837394SDouglas Gilbert 		} else if (sqcp->inj_transport) {
2744c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND,
2745c2248fc9SDouglas Gilbert 					TRANSPORT_PROBLEM, ACK_NAK_TO);
2746c2248fc9SDouglas Gilbert 			return check_condition_result;
2747c4837394SDouglas Gilbert 		} else if (sqcp->inj_dif) {
2748c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
2749c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2750c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2751c4837394SDouglas Gilbert 		} else if (sqcp->inj_dix) {
2752c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2753c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2754c2248fc9SDouglas Gilbert 		}
2755c2248fc9SDouglas Gilbert 	}
2756a4517511SAkinobu Mita 	return 0;
27571da177e4SLinus Torvalds }
27581da177e4SLinus Torvalds 
275958a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len)
2760c6a44287SMartin K. Petersen {
2761cbf67842SDouglas Gilbert 	int i, j, n;
2762c6a44287SMartin K. Petersen 
2763cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
2764c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
2765cbf67842SDouglas Gilbert 		char b[128];
2766c6a44287SMartin K. Petersen 
2767cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
2768c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
2769c6a44287SMartin K. Petersen 
2770cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
2771cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2772cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
2773cbf67842SDouglas Gilbert 			else
2774cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2775cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
2776cbf67842SDouglas Gilbert 		}
2777cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
2778c6a44287SMartin K. Petersen 	}
2779c6a44287SMartin K. Petersen }
2780c6a44287SMartin K. Petersen 
2781c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
2782395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
2783c6a44287SMartin K. Petersen {
2784be4e11beSAkinobu Mita 	int ret;
27856ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
2786be4e11beSAkinobu Mita 	void *daddr;
278765f72f2aSAkinobu Mita 	sector_t sector = start_sec;
2788c6a44287SMartin K. Petersen 	int ppage_offset;
2789be4e11beSAkinobu Mita 	int dpage_offset;
2790be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
2791be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
2792c6a44287SMartin K. Petersen 
2793c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
2794c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2795c6a44287SMartin K. Petersen 
2796be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2797be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
2798be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2799be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2800be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2801c6a44287SMartin K. Petersen 
2802be4e11beSAkinobu Mita 	/* For each protection page */
2803be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
2804be4e11beSAkinobu Mita 		dpage_offset = 0;
2805be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
2806be4e11beSAkinobu Mita 			ret = 0x01;
2807be4e11beSAkinobu Mita 			goto out;
2808c6a44287SMartin K. Petersen 		}
2809c6a44287SMartin K. Petersen 
2810be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
28116ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
2812be4e11beSAkinobu Mita 			/* If we're at the end of the current
2813be4e11beSAkinobu Mita 			 * data page advance to the next one
2814be4e11beSAkinobu Mita 			 */
2815be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
2816be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
2817be4e11beSAkinobu Mita 					ret = 0x01;
2818be4e11beSAkinobu Mita 					goto out;
2819be4e11beSAkinobu Mita 				}
2820be4e11beSAkinobu Mita 				dpage_offset = 0;
2821be4e11beSAkinobu Mita 			}
2822c6a44287SMartin K. Petersen 
2823be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
2824be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
2825be4e11beSAkinobu Mita 
2826be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
2827beb40ea4SAkinobu Mita 			if (ret) {
2828773642d9SDouglas Gilbert 				dump_sector(daddr, sdebug_sector_size);
2829395cef03SMartin K. Petersen 				goto out;
2830395cef03SMartin K. Petersen 			}
2831395cef03SMartin K. Petersen 
2832c6a44287SMartin K. Petersen 			sector++;
2833395cef03SMartin K. Petersen 			ei_lba++;
2834773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
2835c6a44287SMartin K. Petersen 		}
2836be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
2837be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
2838c6a44287SMartin K. Petersen 	}
2839be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2840c6a44287SMartin K. Petersen 
284165f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
2842c6a44287SMartin K. Petersen 	dix_writes++;
2843c6a44287SMartin K. Petersen 
2844c6a44287SMartin K. Petersen 	return 0;
2845c6a44287SMartin K. Petersen 
2846c6a44287SMartin K. Petersen out:
2847c6a44287SMartin K. Petersen 	dif_errors++;
2848be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
2849be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2850c6a44287SMartin K. Petersen 	return ret;
2851c6a44287SMartin K. Petersen }
2852c6a44287SMartin K. Petersen 
2853b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
2854b90ebc3dSAkinobu Mita {
2855773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2856773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2857773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
2858b90ebc3dSAkinobu Mita 	return lba;
2859b90ebc3dSAkinobu Mita }
2860b90ebc3dSAkinobu Mita 
2861b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
2862b90ebc3dSAkinobu Mita {
2863773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
2864a027b5b9SAkinobu Mita 
2865773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2866773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
2867a027b5b9SAkinobu Mita 	return lba;
2868a027b5b9SAkinobu Mita }
2869a027b5b9SAkinobu Mita 
287044d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
287144d92694SMartin K. Petersen {
2872b90ebc3dSAkinobu Mita 	sector_t end;
2873b90ebc3dSAkinobu Mita 	unsigned int mapped;
2874b90ebc3dSAkinobu Mita 	unsigned long index;
2875b90ebc3dSAkinobu Mita 	unsigned long next;
287644d92694SMartin K. Petersen 
2877b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
2878b90ebc3dSAkinobu Mita 	mapped = test_bit(index, map_storep);
287944d92694SMartin K. Petersen 
288044d92694SMartin K. Petersen 	if (mapped)
2881b90ebc3dSAkinobu Mita 		next = find_next_zero_bit(map_storep, map_size, index);
288244d92694SMartin K. Petersen 	else
2883b90ebc3dSAkinobu Mita 		next = find_next_bit(map_storep, map_size, index);
288444d92694SMartin K. Petersen 
2885b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
288644d92694SMartin K. Petersen 	*num = end - lba;
288744d92694SMartin K. Petersen 	return mapped;
288844d92694SMartin K. Petersen }
288944d92694SMartin K. Petersen 
289044d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
289144d92694SMartin K. Petersen {
289244d92694SMartin K. Petersen 	sector_t end = lba + len;
289344d92694SMartin K. Petersen 
289444d92694SMartin K. Petersen 	while (lba < end) {
2895b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
289644d92694SMartin K. Petersen 
2897b90ebc3dSAkinobu Mita 		if (index < map_size)
2898b90ebc3dSAkinobu Mita 			set_bit(index, map_storep);
289944d92694SMartin K. Petersen 
2900b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
290144d92694SMartin K. Petersen 	}
290244d92694SMartin K. Petersen }
290344d92694SMartin K. Petersen 
290444d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
290544d92694SMartin K. Petersen {
290644d92694SMartin K. Petersen 	sector_t end = lba + len;
290744d92694SMartin K. Petersen 
290844d92694SMartin K. Petersen 	while (lba < end) {
2909b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
291044d92694SMartin K. Petersen 
2911b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
2912773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
2913b90ebc3dSAkinobu Mita 		    index < map_size) {
2914b90ebc3dSAkinobu Mita 			clear_bit(index, map_storep);
2915760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
2916be1dd78dSEric Sandeen 				memset(fake_storep +
2917760f3b03SDouglas Gilbert 				       lba * sdebug_sector_size,
2918760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
2919773642d9SDouglas Gilbert 				       sdebug_sector_size *
2920773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2921be1dd78dSEric Sandeen 			}
2922e9926b43SAkinobu Mita 			if (dif_storep) {
2923e9926b43SAkinobu Mita 				memset(dif_storep + lba, 0xff,
2924e9926b43SAkinobu Mita 				       sizeof(*dif_storep) *
2925773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2926e9926b43SAkinobu Mita 			}
2927b90ebc3dSAkinobu Mita 		}
2928b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
292944d92694SMartin K. Petersen 	}
293044d92694SMartin K. Petersen }
293144d92694SMartin K. Petersen 
2932fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
29331da177e4SLinus Torvalds {
2934c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2935c2248fc9SDouglas Gilbert 	u64 lba;
2936c2248fc9SDouglas Gilbert 	u32 num;
2937c2248fc9SDouglas Gilbert 	u32 ei_lba;
29381da177e4SLinus Torvalds 	unsigned long iflags;
293919789100SFUJITA Tomonori 	int ret;
2940c2248fc9SDouglas Gilbert 	bool check_prot;
29411da177e4SLinus Torvalds 
2942c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2943c2248fc9SDouglas Gilbert 	case WRITE_16:
2944c2248fc9SDouglas Gilbert 		ei_lba = 0;
2945c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2946c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2947c2248fc9SDouglas Gilbert 		check_prot = true;
2948c2248fc9SDouglas Gilbert 		break;
2949c2248fc9SDouglas Gilbert 	case WRITE_10:
2950c2248fc9SDouglas Gilbert 		ei_lba = 0;
2951c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2952c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2953c2248fc9SDouglas Gilbert 		check_prot = true;
2954c2248fc9SDouglas Gilbert 		break;
2955c2248fc9SDouglas Gilbert 	case WRITE_6:
2956c2248fc9SDouglas Gilbert 		ei_lba = 0;
2957c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2958c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2959c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2960c2248fc9SDouglas Gilbert 		check_prot = true;
2961c2248fc9SDouglas Gilbert 		break;
2962c2248fc9SDouglas Gilbert 	case WRITE_12:
2963c2248fc9SDouglas Gilbert 		ei_lba = 0;
2964c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2965c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2966c2248fc9SDouglas Gilbert 		check_prot = true;
2967c2248fc9SDouglas Gilbert 		break;
2968c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
2969c2248fc9SDouglas Gilbert 		ei_lba = 0;
2970c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2971c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2972c2248fc9SDouglas Gilbert 		check_prot = false;
2973c2248fc9SDouglas Gilbert 		break;
2974c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
2975c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2976c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2977c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2978c2248fc9SDouglas Gilbert 		check_prot = false;
2979c2248fc9SDouglas Gilbert 		break;
2980c2248fc9SDouglas Gilbert 	}
2981f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
29828475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2983c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2984c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2985c2248fc9SDouglas Gilbert 			return check_condition_result;
2986c2248fc9SDouglas Gilbert 		}
29878475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
29888475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
2989c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2990c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2991c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2992c2248fc9SDouglas Gilbert 	}
2993c2248fc9SDouglas Gilbert 
2994c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2995f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
2996c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2997c2248fc9SDouglas Gilbert 		return check_condition_result;
2998c2248fc9SDouglas Gilbert 	}
2999c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
3000f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
3001c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
3002c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3003c2248fc9SDouglas Gilbert 		return check_condition_result;
3004c2248fc9SDouglas Gilbert 	}
30051da177e4SLinus Torvalds 
30066c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
30076c78cc06SAkinobu Mita 
3008c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3009f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3010c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
3011c6a44287SMartin K. Petersen 
3012c6a44287SMartin K. Petersen 		if (prot_ret) {
30136c78cc06SAkinobu Mita 			write_unlock_irqrestore(&atomic_rw, iflags);
3014c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
3015c6a44287SMartin K. Petersen 			return illegal_condition_result;
3016c6a44287SMartin K. Petersen 		}
3017c6a44287SMartin K. Petersen 	}
3018c6a44287SMartin K. Petersen 
30190a7e69c7SDouglas Gilbert 	ret = do_device_access(scp, 0, lba, num, true);
3020f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
302144d92694SMartin K. Petersen 		map_region(lba, num);
30221da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
3023f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3024773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3025c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3026c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3027c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3028cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3029773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
303044d92694SMartin K. Petersen 
3031f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
3032c4837394SDouglas Gilbert 		struct sdebug_queued_cmd *sqcp =
3033c4837394SDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
3034c2248fc9SDouglas Gilbert 
3035c4837394SDouglas Gilbert 		if (sqcp) {
3036c4837394SDouglas Gilbert 			if (sqcp->inj_recovered) {
3037c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR,
3038c2248fc9SDouglas Gilbert 						THRESHOLD_EXCEEDED, 0);
3039c2248fc9SDouglas Gilbert 				return check_condition_result;
3040c4837394SDouglas Gilbert 			} else if (sqcp->inj_dif) {
3041c2248fc9SDouglas Gilbert 				/* Logical block guard check failed */
3042c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3043c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3044c4837394SDouglas Gilbert 			} else if (sqcp->inj_dix) {
3045c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3046c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3047c2248fc9SDouglas Gilbert 			}
3048c2248fc9SDouglas Gilbert 		}
3049c4837394SDouglas Gilbert 	}
30501da177e4SLinus Torvalds 	return 0;
30511da177e4SLinus Torvalds }
30521da177e4SLinus Torvalds 
3053fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3054fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
305544d92694SMartin K. Petersen {
305644d92694SMartin K. Petersen 	unsigned long iflags;
305744d92694SMartin K. Petersen 	unsigned long long i;
305844d92694SMartin K. Petersen 	int ret;
3059773642d9SDouglas Gilbert 	u64 lba_off;
306044d92694SMartin K. Petersen 
3061c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num);
306244d92694SMartin K. Petersen 	if (ret)
306344d92694SMartin K. Petersen 		return ret;
306444d92694SMartin K. Petersen 
306544d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
306644d92694SMartin K. Petersen 
30679ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
306844d92694SMartin K. Petersen 		unmap_region(lba, num);
306944d92694SMartin K. Petersen 		goto out;
307044d92694SMartin K. Petersen 	}
307144d92694SMartin K. Petersen 
3072773642d9SDouglas Gilbert 	lba_off = lba * sdebug_sector_size;
3073c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
3074c2248fc9SDouglas Gilbert 	if (ndob) {
3075773642d9SDouglas Gilbert 		memset(fake_storep + lba_off, 0, sdebug_sector_size);
3076c2248fc9SDouglas Gilbert 		ret = 0;
3077c2248fc9SDouglas Gilbert 	} else
3078773642d9SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
3079773642d9SDouglas Gilbert 					  sdebug_sector_size);
308044d92694SMartin K. Petersen 
308144d92694SMartin K. Petersen 	if (-1 == ret) {
308244d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
3083773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3084e33d7c56SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < sdebug_sector_size))
3085c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3086e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
3087cbf67842SDouglas Gilbert 			    my_name, "write same",
3088e33d7c56SDouglas Gilbert 			    sdebug_sector_size, ret);
308944d92694SMartin K. Petersen 
309044d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
309144d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
3092773642d9SDouglas Gilbert 		memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
3093773642d9SDouglas Gilbert 		       fake_storep + lba_off,
3094773642d9SDouglas Gilbert 		       sdebug_sector_size);
309544d92694SMartin K. Petersen 
30969ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
309744d92694SMartin K. Petersen 		map_region(lba, num);
309844d92694SMartin K. Petersen out:
309944d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
310044d92694SMartin K. Petersen 
310144d92694SMartin K. Petersen 	return 0;
310244d92694SMartin K. Petersen }
310344d92694SMartin K. Petersen 
3104fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3105fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3106c2248fc9SDouglas Gilbert {
3107c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3108c2248fc9SDouglas Gilbert 	u32 lba;
3109c2248fc9SDouglas Gilbert 	u16 num;
3110c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3111c2248fc9SDouglas Gilbert 	bool unmap = false;
3112c2248fc9SDouglas Gilbert 
3113c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3114773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3115c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3116c2248fc9SDouglas Gilbert 			return check_condition_result;
3117c2248fc9SDouglas Gilbert 		} else
3118c2248fc9SDouglas Gilbert 			unmap = true;
3119c2248fc9SDouglas Gilbert 	}
3120c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3121c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3122773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3123c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3124c2248fc9SDouglas Gilbert 		return check_condition_result;
3125c2248fc9SDouglas Gilbert 	}
3126c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3127c2248fc9SDouglas Gilbert }
3128c2248fc9SDouglas Gilbert 
3129fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3130fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3131c2248fc9SDouglas Gilbert {
3132c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3133c2248fc9SDouglas Gilbert 	u64 lba;
3134c2248fc9SDouglas Gilbert 	u32 num;
3135c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3136c2248fc9SDouglas Gilbert 	bool unmap = false;
3137c2248fc9SDouglas Gilbert 	bool ndob = false;
3138c2248fc9SDouglas Gilbert 
3139c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3140773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3141c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3142c2248fc9SDouglas Gilbert 			return check_condition_result;
3143c2248fc9SDouglas Gilbert 		} else
3144c2248fc9SDouglas Gilbert 			unmap = true;
3145c2248fc9SDouglas Gilbert 	}
3146c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3147c2248fc9SDouglas Gilbert 		ndob = true;
3148c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3149c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3150773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3151c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3152c2248fc9SDouglas Gilbert 		return check_condition_result;
3153c2248fc9SDouglas Gilbert 	}
3154c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3155c2248fc9SDouglas Gilbert }
3156c2248fc9SDouglas Gilbert 
3157acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3158acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3159acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3160fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3161fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3162acafd0b9SEwan D. Milne {
3163acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3164acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3165acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3166acafd0b9SEwan D. Milne 	u8 mode;
3167acafd0b9SEwan D. Milne 
3168acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3169acafd0b9SEwan D. Milne 	switch (mode) {
3170acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3171acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3172acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3173acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3174acafd0b9SEwan D. Milne 		break;
3175acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3176acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3177acafd0b9SEwan D. Milne 		break;
3178acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3179acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3180acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3181acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3182acafd0b9SEwan D. Milne 				    dev_list)
3183acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3184acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3185acafd0b9SEwan D. Milne 				if (devip != dp)
3186acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3187acafd0b9SEwan D. Milne 						dp->uas_bm);
3188acafd0b9SEwan D. Milne 			}
3189acafd0b9SEwan D. Milne 		break;
3190acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3191acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3192acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3193acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3194acafd0b9SEwan D. Milne 				    dev_list)
3195acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3196acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3197acafd0b9SEwan D. Milne 					dp->uas_bm);
3198acafd0b9SEwan D. Milne 		break;
3199acafd0b9SEwan D. Milne 	default:
3200acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3201acafd0b9SEwan D. Milne 		break;
3202acafd0b9SEwan D. Milne 	}
3203acafd0b9SEwan D. Milne 	return 0;
3204acafd0b9SEwan D. Milne }
3205acafd0b9SEwan D. Milne 
3206fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3207fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
320838d5c833SDouglas Gilbert {
320938d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
321038d5c833SDouglas Gilbert 	u8 *arr;
321138d5c833SDouglas Gilbert 	u8 *fake_storep_hold;
321238d5c833SDouglas Gilbert 	u64 lba;
321338d5c833SDouglas Gilbert 	u32 dnum;
3214773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
321538d5c833SDouglas Gilbert 	u8 num;
321638d5c833SDouglas Gilbert 	unsigned long iflags;
321738d5c833SDouglas Gilbert 	int ret;
3218d467d31fSDouglas Gilbert 	int retval = 0;
321938d5c833SDouglas Gilbert 
3220d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
322138d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
322238d5c833SDouglas Gilbert 	if (0 == num)
322338d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
32248475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
322538d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
322638d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
322738d5c833SDouglas Gilbert 		return check_condition_result;
322838d5c833SDouglas Gilbert 	}
32298475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
32308475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
323138d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
323238d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
323338d5c833SDouglas Gilbert 			    "to DIF device\n");
323438d5c833SDouglas Gilbert 
323538d5c833SDouglas Gilbert 	/* inline check_device_access_params() */
323638d5c833SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
323738d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
323838d5c833SDouglas Gilbert 		return check_condition_result;
323938d5c833SDouglas Gilbert 	}
324038d5c833SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
324138d5c833SDouglas Gilbert 	if (num > sdebug_store_sectors) {
324238d5c833SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
324338d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
324438d5c833SDouglas Gilbert 		return check_condition_result;
324538d5c833SDouglas Gilbert 	}
3246d467d31fSDouglas Gilbert 	dnum = 2 * num;
3247d467d31fSDouglas Gilbert 	arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3248d467d31fSDouglas Gilbert 	if (NULL == arr) {
3249d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3250d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3251d467d31fSDouglas Gilbert 		return check_condition_result;
3252d467d31fSDouglas Gilbert 	}
325338d5c833SDouglas Gilbert 
325438d5c833SDouglas Gilbert 	write_lock_irqsave(&atomic_rw, iflags);
325538d5c833SDouglas Gilbert 
325638d5c833SDouglas Gilbert 	/* trick do_device_access() to fetch both compare and write buffers
325738d5c833SDouglas Gilbert 	 * from data-in into arr. Safe (atomic) since write_lock held. */
325838d5c833SDouglas Gilbert 	fake_storep_hold = fake_storep;
325938d5c833SDouglas Gilbert 	fake_storep = arr;
32600a7e69c7SDouglas Gilbert 	ret = do_device_access(scp, 0, 0, dnum, true);
326138d5c833SDouglas Gilbert 	fake_storep = fake_storep_hold;
326238d5c833SDouglas Gilbert 	if (ret == -1) {
3263d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3264d467d31fSDouglas Gilbert 		goto cleanup;
3265773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
326638d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
326738d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
326838d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
326938d5c833SDouglas Gilbert 	if (!comp_write_worker(lba, num, arr)) {
327038d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3271d467d31fSDouglas Gilbert 		retval = check_condition_result;
3272d467d31fSDouglas Gilbert 		goto cleanup;
327338d5c833SDouglas Gilbert 	}
327438d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
327538d5c833SDouglas Gilbert 		map_region(lba, num);
3276d467d31fSDouglas Gilbert cleanup:
327738d5c833SDouglas Gilbert 	write_unlock_irqrestore(&atomic_rw, iflags);
3278d467d31fSDouglas Gilbert 	kfree(arr);
3279d467d31fSDouglas Gilbert 	return retval;
328038d5c833SDouglas Gilbert }
328138d5c833SDouglas Gilbert 
328244d92694SMartin K. Petersen struct unmap_block_desc {
328344d92694SMartin K. Petersen 	__be64	lba;
328444d92694SMartin K. Petersen 	__be32	blocks;
328544d92694SMartin K. Petersen 	__be32	__reserved;
328644d92694SMartin K. Petersen };
328744d92694SMartin K. Petersen 
3288fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
328944d92694SMartin K. Petersen {
329044d92694SMartin K. Petersen 	unsigned char *buf;
329144d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
329244d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
329344d92694SMartin K. Petersen 	int ret;
32946c78cc06SAkinobu Mita 	unsigned long iflags;
329544d92694SMartin K. Petersen 
329644d92694SMartin K. Petersen 
3297c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3298c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3299c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3300c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
330144d92694SMartin K. Petersen 
330244d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3303773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3304c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
330544d92694SMartin K. Petersen 		return check_condition_result;
3306c2248fc9SDouglas Gilbert 	}
330744d92694SMartin K. Petersen 
3308b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3309c2248fc9SDouglas Gilbert 	if (!buf) {
3310c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3311c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3312c2248fc9SDouglas Gilbert 		return check_condition_result;
3313c2248fc9SDouglas Gilbert 	}
3314c2248fc9SDouglas Gilbert 
3315c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
331644d92694SMartin K. Petersen 
331744d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
331844d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
331944d92694SMartin K. Petersen 
332044d92694SMartin K. Petersen 	desc = (void *)&buf[8];
332144d92694SMartin K. Petersen 
33226c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
33236c78cc06SAkinobu Mita 
332444d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
332544d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
332644d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
332744d92694SMartin K. Petersen 
3328c2248fc9SDouglas Gilbert 		ret = check_device_access_params(scp, lba, num);
332944d92694SMartin K. Petersen 		if (ret)
333044d92694SMartin K. Petersen 			goto out;
333144d92694SMartin K. Petersen 
333244d92694SMartin K. Petersen 		unmap_region(lba, num);
333344d92694SMartin K. Petersen 	}
333444d92694SMartin K. Petersen 
333544d92694SMartin K. Petersen 	ret = 0;
333644d92694SMartin K. Petersen 
333744d92694SMartin K. Petersen out:
33386c78cc06SAkinobu Mita 	write_unlock_irqrestore(&atomic_rw, iflags);
333944d92694SMartin K. Petersen 	kfree(buf);
334044d92694SMartin K. Petersen 
334144d92694SMartin K. Petersen 	return ret;
334244d92694SMartin K. Petersen }
334344d92694SMartin K. Petersen 
334444d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
334544d92694SMartin K. Petersen 
3346fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
3347fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
334844d92694SMartin K. Petersen {
3349c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3350c2248fc9SDouglas Gilbert 	u64 lba;
3351c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
3352c2248fc9SDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
335344d92694SMartin K. Petersen 	int ret;
335444d92694SMartin K. Petersen 
3355c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3356c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
335744d92694SMartin K. Petersen 
335844d92694SMartin K. Petersen 	if (alloc_len < 24)
335944d92694SMartin K. Petersen 		return 0;
336044d92694SMartin K. Petersen 
3361c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, 1);
336244d92694SMartin K. Petersen 	if (ret)
336344d92694SMartin K. Petersen 		return ret;
336444d92694SMartin K. Petersen 
3365c2248fc9SDouglas Gilbert 	if (scsi_debug_lbp())
336644d92694SMartin K. Petersen 		mapped = map_state(lba, &num);
3367c2248fc9SDouglas Gilbert 	else {
3368c2248fc9SDouglas Gilbert 		mapped = 1;
3369c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
3370c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
3371c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
3372c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
3373c2248fc9SDouglas Gilbert 		else
3374c2248fc9SDouglas Gilbert 			num = 0xffffffff;
3375c2248fc9SDouglas Gilbert 	}
337644d92694SMartin K. Petersen 
337744d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
3378c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
3379c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
3380c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
3381c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
338244d92694SMartin K. Petersen 
3383c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
338444d92694SMartin K. Petersen }
338544d92694SMartin K. Petersen 
3386fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
3387fb0cc8d1SDouglas Gilbert 
33888d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
33898d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
33908d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
33918d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
33928d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
33938d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
33948d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
33958d039e22SDouglas Gilbert  */
33961da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
33971da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
33981da177e4SLinus Torvalds {
339901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
34008d039e22SDouglas Gilbert 	unsigned int alloc_len;
34018d039e22SDouglas Gilbert 	unsigned char select_report;
34028d039e22SDouglas Gilbert 	u64 lun;
34038d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
3404fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
34058d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
34068d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
34078d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
34088d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
3409fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
3410fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
3411fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
34121da177e4SLinus Torvalds 
341319c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
34148d039e22SDouglas Gilbert 
34158d039e22SDouglas Gilbert 	select_report = cmd[2];
34168d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
34178d039e22SDouglas Gilbert 
34188d039e22SDouglas Gilbert 	if (alloc_len < 4) {
34198d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
34208d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
34211da177e4SLinus Torvalds 		return check_condition_result;
34221da177e4SLinus Torvalds 	}
34238d039e22SDouglas Gilbert 
34248d039e22SDouglas Gilbert 	switch (select_report) {
34258d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
3426773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
34278d039e22SDouglas Gilbert 		wlun_cnt = 0;
34288d039e22SDouglas Gilbert 		break;
34298d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
3430c65b1445SDouglas Gilbert 		lun_cnt = 0;
34318d039e22SDouglas Gilbert 		wlun_cnt = 1;
34328d039e22SDouglas Gilbert 		break;
34338d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
34348d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
34358d039e22SDouglas Gilbert 		wlun_cnt = 1;
34368d039e22SDouglas Gilbert 		break;
34378d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
34388d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
34398d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
34408d039e22SDouglas Gilbert 	default:
34418d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
34428d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
34438d039e22SDouglas Gilbert 		return check_condition_result;
34448d039e22SDouglas Gilbert 	}
34458d039e22SDouglas Gilbert 
34468d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
3447c65b1445SDouglas Gilbert 		--lun_cnt;
34488d039e22SDouglas Gilbert 
34498d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
3450fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
3451fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
34528d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
34538d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
34548d039e22SDouglas Gilbert 
3455fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
34568d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
3457fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3458fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
3459fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
3460fb0cc8d1SDouglas Gilbert 		if (k == 0) {
3461fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
3462fb0cc8d1SDouglas Gilbert 			++lun_p;
3463fb0cc8d1SDouglas Gilbert 			j = 1;
3464fb0cc8d1SDouglas Gilbert 		}
3465fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3466fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3467fb0cc8d1SDouglas Gilbert 				break;
3468fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
3469fb0cc8d1SDouglas Gilbert 		}
3470fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
3471fb0cc8d1SDouglas Gilbert 			break;
3472fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
3473fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3474fb0cc8d1SDouglas Gilbert 		if (res)
3475fb0cc8d1SDouglas Gilbert 			return res;
3476fb0cc8d1SDouglas Gilbert 		off_rsp += n;
3477fb0cc8d1SDouglas Gilbert 	}
3478fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
3479fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3480fb0cc8d1SDouglas Gilbert 		++j;
3481fb0cc8d1SDouglas Gilbert 	}
3482fb0cc8d1SDouglas Gilbert 	if (j > 0)
3483fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
34848d039e22SDouglas Gilbert 	return res;
34851da177e4SLinus Torvalds }
34861da177e4SLinus Torvalds 
3487c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3488c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
3489c639d14eSFUJITA Tomonori {
3490be4e11beSAkinobu Mita 	int j;
3491c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
3492c639d14eSFUJITA Tomonori 	unsigned int offset;
3493c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
3494be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3495c639d14eSFUJITA Tomonori 
3496c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
3497b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3498c5af0db9SAkinobu Mita 	if (!buf) {
349922017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
350022017ed2SDouglas Gilbert 				INSUFF_RES_ASCQ);
3501c5af0db9SAkinobu Mita 		return check_condition_result;
3502c5af0db9SAkinobu Mita 	}
3503c639d14eSFUJITA Tomonori 
350421a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
3505c639d14eSFUJITA Tomonori 
3506c639d14eSFUJITA Tomonori 	offset = 0;
3507be4e11beSAkinobu Mita 	sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3508be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_TO_SG);
3509c639d14eSFUJITA Tomonori 
3510be4e11beSAkinobu Mita 	while (sg_miter_next(&miter)) {
3511be4e11beSAkinobu Mita 		kaddr = miter.addr;
3512be4e11beSAkinobu Mita 		for (j = 0; j < miter.length; j++)
3513be4e11beSAkinobu Mita 			*(kaddr + j) ^= *(buf + offset + j);
3514c639d14eSFUJITA Tomonori 
3515be4e11beSAkinobu Mita 		offset += miter.length;
3516c639d14eSFUJITA Tomonori 	}
3517be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3518c639d14eSFUJITA Tomonori 	kfree(buf);
3519c639d14eSFUJITA Tomonori 
3520be4e11beSAkinobu Mita 	return 0;
3521c639d14eSFUJITA Tomonori }
3522c639d14eSFUJITA Tomonori 
3523fd32119bSDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3524fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
3525c2248fc9SDouglas Gilbert {
3526c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3527c2248fc9SDouglas Gilbert 	u64 lba;
3528c2248fc9SDouglas Gilbert 	u32 num;
3529c2248fc9SDouglas Gilbert 	int errsts;
3530c2248fc9SDouglas Gilbert 
3531c2248fc9SDouglas Gilbert 	if (!scsi_bidi_cmnd(scp)) {
3532c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3533c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3534c2248fc9SDouglas Gilbert 		return check_condition_result;
3535c2248fc9SDouglas Gilbert 	}
3536c2248fc9SDouglas Gilbert 	errsts = resp_read_dt0(scp, devip);
3537c2248fc9SDouglas Gilbert 	if (errsts)
3538c2248fc9SDouglas Gilbert 		return errsts;
3539c2248fc9SDouglas Gilbert 	if (!(cmd[1] & 0x4)) {		/* DISABLE_WRITE is not set */
3540c2248fc9SDouglas Gilbert 		errsts = resp_write_dt0(scp, devip);
3541c2248fc9SDouglas Gilbert 		if (errsts)
3542c2248fc9SDouglas Gilbert 			return errsts;
3543c2248fc9SDouglas Gilbert 	}
3544c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3545c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3546c2248fc9SDouglas Gilbert 	return resp_xdwriteread(scp, lba, num, devip);
3547c2248fc9SDouglas Gilbert }
3548c2248fc9SDouglas Gilbert 
3549c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3550c4837394SDouglas Gilbert {
3551c4837394SDouglas Gilbert 	struct sdebug_queue *sqp = sdebug_q_arr;
3552c4837394SDouglas Gilbert 
3553c4837394SDouglas Gilbert 	if (sdebug_mq_active) {
3554c4837394SDouglas Gilbert 		u32 tag = blk_mq_unique_tag(cmnd->request);
3555c4837394SDouglas Gilbert 		u16 hwq = blk_mq_unique_tag_to_hwq(tag);
3556c4837394SDouglas Gilbert 
3557c4837394SDouglas Gilbert 		if (unlikely(hwq >= submit_queues)) {
3558c4837394SDouglas Gilbert 			pr_warn("Unexpected hwq=%d, apply modulo\n", hwq);
3559c4837394SDouglas Gilbert 			hwq %= submit_queues;
3560c4837394SDouglas Gilbert 		}
3561c4837394SDouglas Gilbert 		pr_debug("tag=%u, hwq=%d\n", tag, hwq);
3562c4837394SDouglas Gilbert 		return sqp + hwq;
3563c4837394SDouglas Gilbert 	} else
3564c4837394SDouglas Gilbert 		return sqp;
3565c4837394SDouglas Gilbert }
3566c4837394SDouglas Gilbert 
3567c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
3568fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
35691da177e4SLinus Torvalds {
3570c4837394SDouglas Gilbert 	int qc_idx;
3571cbf67842SDouglas Gilbert 	int retiring = 0;
35721da177e4SLinus Torvalds 	unsigned long iflags;
3573c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3574cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3575cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
3576cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
35771da177e4SLinus Torvalds 
3578c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
3579c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
3580c4837394SDouglas Gilbert 	if (sdebug_statistics) {
3581cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
3582c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3583c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
3584c4837394SDouglas Gilbert 	}
3585c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3586c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
35871da177e4SLinus Torvalds 		return;
35881da177e4SLinus Torvalds 	}
3589c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
3590c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
3591cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
3592b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
3593c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3594c4837394SDouglas Gilbert 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3595c4837394SDouglas Gilbert 		       sd_dp->sqa_idx, qc_idx);
35961da177e4SLinus Torvalds 		return;
35971da177e4SLinus Torvalds 	}
3598cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
3599f46eb0e9SDouglas Gilbert 	if (likely(devip))
3600cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
3601cbf67842SDouglas Gilbert 	else
3602c1287970STomas Winkler 		pr_err("devip=NULL\n");
3603f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
3604cbf67842SDouglas Gilbert 		retiring = 1;
3605cbf67842SDouglas Gilbert 
3606cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
3607c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3608c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3609c1287970STomas Winkler 		pr_err("Unexpected completion\n");
3610cbf67842SDouglas Gilbert 		return;
36111da177e4SLinus Torvalds 	}
36121da177e4SLinus Torvalds 
3613cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
3614cbf67842SDouglas Gilbert 		int k, retval;
3615cbf67842SDouglas Gilbert 
3616cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
3617c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
3618c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3619c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
3620cbf67842SDouglas Gilbert 			return;
3621cbf67842SDouglas Gilbert 		}
3622c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
3623773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
3624cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3625cbf67842SDouglas Gilbert 		else
3626cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
3627cbf67842SDouglas Gilbert 	}
3628c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3629cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
3630cbf67842SDouglas Gilbert }
3631cbf67842SDouglas Gilbert 
3632cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
3633fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
3634cbf67842SDouglas Gilbert {
3635a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3636a10bc12aSDouglas Gilbert 						  hrt);
3637a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3638cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
3639cbf67842SDouglas Gilbert }
36401da177e4SLinus Torvalds 
3641a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
3642fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
3643a10bc12aSDouglas Gilbert {
3644a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3645a10bc12aSDouglas Gilbert 						  ew.work);
3646a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3647a10bc12aSDouglas Gilbert }
3648a10bc12aSDouglas Gilbert 
364909ba24c1SDouglas Gilbert static bool got_shared_uuid;
3650bf476433SChristoph Hellwig static uuid_t shared_uuid;
365109ba24c1SDouglas Gilbert 
3652fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
3653fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
36545cb2fc06SFUJITA Tomonori {
36555cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
36565cb2fc06SFUJITA Tomonori 
36575cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
36585cb2fc06SFUJITA Tomonori 	if (devip) {
365909ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
3660bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
366109ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
366209ba24c1SDouglas Gilbert 			if (got_shared_uuid)
366309ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
366409ba24c1SDouglas Gilbert 			else {
3665bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
366609ba24c1SDouglas Gilbert 				got_shared_uuid = true;
366709ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
366809ba24c1SDouglas Gilbert 			}
366909ba24c1SDouglas Gilbert 		}
36705cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
36715cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
36725cb2fc06SFUJITA Tomonori 	}
36735cb2fc06SFUJITA Tomonori 	return devip;
36745cb2fc06SFUJITA Tomonori }
36755cb2fc06SFUJITA Tomonori 
3676f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
36771da177e4SLinus Torvalds {
36781da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
36791da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
3680f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
36811da177e4SLinus Torvalds 
3682d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
36831da177e4SLinus Torvalds 	if (!sdbg_host) {
3684c1287970STomas Winkler 		pr_err("Host info NULL\n");
36851da177e4SLinus Torvalds 		return NULL;
36861da177e4SLinus Torvalds 	}
36871da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
36881da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
36891da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
36901da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
36911da177e4SLinus Torvalds 			return devip;
36921da177e4SLinus Torvalds 		else {
36931da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
36941da177e4SLinus Torvalds 				open_devip = devip;
36951da177e4SLinus Torvalds 		}
36961da177e4SLinus Torvalds 	}
36975cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
36985cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
36995cb2fc06SFUJITA Tomonori 		if (!open_devip) {
3700c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
37011da177e4SLinus Torvalds 			return NULL;
37021da177e4SLinus Torvalds 		}
37031da177e4SLinus Torvalds 	}
3704a75869d1SFUJITA Tomonori 
37051da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
37061da177e4SLinus Torvalds 	open_devip->target = sdev->id;
37071da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
37081da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
3709cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
3710cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
3711c2248fc9SDouglas Gilbert 	open_devip->used = true;
37121da177e4SLinus Torvalds 	return open_devip;
37131da177e4SLinus Torvalds }
37141da177e4SLinus Torvalds 
37158dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
37161da177e4SLinus Torvalds {
3717773642d9SDouglas Gilbert 	if (sdebug_verbose)
3718c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
37198dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
372075ad23bcSNick Piggin 	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
37218dea0d02SFUJITA Tomonori 	return 0;
37228dea0d02SFUJITA Tomonori }
37231da177e4SLinus Torvalds 
37248dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
37258dea0d02SFUJITA Tomonori {
3726f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
3727f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
3728a34c4e98SFUJITA Tomonori 
3729773642d9SDouglas Gilbert 	if (sdebug_verbose)
3730c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
37318dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3732b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3733b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3734b01f6f83SDouglas Gilbert 	if (devip == NULL) {
3735f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
3736b01f6f83SDouglas Gilbert 		if (devip == NULL)
37378dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
3738f46eb0e9SDouglas Gilbert 	}
3739c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
37406bb5e6e7SAkinobu Mita 	blk_queue_max_segment_size(sdp->request_queue, -1U);
3741773642d9SDouglas Gilbert 	if (sdebug_no_uld)
374278d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
37439b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
37448dea0d02SFUJITA Tomonori 	return 0;
37458dea0d02SFUJITA Tomonori }
37468dea0d02SFUJITA Tomonori 
37478dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
37488dea0d02SFUJITA Tomonori {
37498dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
37508dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
37518dea0d02SFUJITA Tomonori 
3752773642d9SDouglas Gilbert 	if (sdebug_verbose)
3753c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
37548dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
37558dea0d02SFUJITA Tomonori 	if (devip) {
375625985edcSLucas De Marchi 		/* make this slot available for re-use */
3757c2248fc9SDouglas Gilbert 		devip->used = false;
37588dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
37598dea0d02SFUJITA Tomonori 	}
37608dea0d02SFUJITA Tomonori }
37618dea0d02SFUJITA Tomonori 
3762c4837394SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp)
3763c4837394SDouglas Gilbert {
3764c4837394SDouglas Gilbert 	if (!sd_dp)
3765c4837394SDouglas Gilbert 		return;
3766c4837394SDouglas Gilbert 	if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0))
3767c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
3768c4837394SDouglas Gilbert 	else if (sdebug_jdelay < 0)
3769c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
3770c4837394SDouglas Gilbert }
3771c4837394SDouglas Gilbert 
3772a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
3773a10bc12aSDouglas Gilbert    returns false */
3774a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
37758dea0d02SFUJITA Tomonori {
37768dea0d02SFUJITA Tomonori 	unsigned long iflags;
3777c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
3778c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
37798dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3780cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3781a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
37828dea0d02SFUJITA Tomonori 
3783c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3784c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
3785773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
3786cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
3787cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
3788cbf67842SDouglas Gilbert 			qmax = r_qmax;
3789cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
3790c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
3791c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
3792a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
3793a10bc12aSDouglas Gilbert 					continue;
3794c4837394SDouglas Gilbert 				/* found */
3795db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3796db525fceSDouglas Gilbert 						cmnd->device->hostdata;
3797db525fceSDouglas Gilbert 				if (devip)
3798db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3799db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3800a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
3801c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3802c4837394SDouglas Gilbert 				stop_qc_helper(sd_dp);
3803c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
3804a10bc12aSDouglas Gilbert 				return true;
38058dea0d02SFUJITA Tomonori 			}
3806cbf67842SDouglas Gilbert 		}
3807c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3808c4837394SDouglas Gilbert 	}
3809a10bc12aSDouglas Gilbert 	return false;
38108dea0d02SFUJITA Tomonori }
38118dea0d02SFUJITA Tomonori 
3812a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
38138dea0d02SFUJITA Tomonori static void stop_all_queued(void)
38148dea0d02SFUJITA Tomonori {
38158dea0d02SFUJITA Tomonori 	unsigned long iflags;
3816c4837394SDouglas Gilbert 	int j, k;
3817c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
38188dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3819cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3820a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
38218dea0d02SFUJITA Tomonori 
3822c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3823c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
3824c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3825c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
3826c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
3827c4837394SDouglas Gilbert 				if (sqcp->a_cmnd == NULL)
3828a10bc12aSDouglas Gilbert 					continue;
3829db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3830db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
3831db525fceSDouglas Gilbert 				if (devip)
3832db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3833db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3834a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
3835c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3836c4837394SDouglas Gilbert 				stop_qc_helper(sd_dp);
3837c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
3838c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
38398dea0d02SFUJITA Tomonori 			}
38408dea0d02SFUJITA Tomonori 		}
3841c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3842c4837394SDouglas Gilbert 	}
3843cbf67842SDouglas Gilbert }
3844cbf67842SDouglas Gilbert 
3845cbf67842SDouglas Gilbert /* Free queued command memory on heap */
3846cbf67842SDouglas Gilbert static void free_all_queued(void)
3847cbf67842SDouglas Gilbert {
3848c4837394SDouglas Gilbert 	int j, k;
3849c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3850cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3851cbf67842SDouglas Gilbert 
3852c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3853c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3854c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
3855a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
3856a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
3857cbf67842SDouglas Gilbert 		}
38581da177e4SLinus Torvalds 	}
3859c4837394SDouglas Gilbert }
38601da177e4SLinus Torvalds 
38611da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
38621da177e4SLinus Torvalds {
3863a10bc12aSDouglas Gilbert 	bool ok;
3864a10bc12aSDouglas Gilbert 
38651da177e4SLinus Torvalds 	++num_aborts;
3866cbf67842SDouglas Gilbert 	if (SCpnt) {
3867a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
3868a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3869a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
3870a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
3871a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
3872cbf67842SDouglas Gilbert 	}
38731da177e4SLinus Torvalds 	return SUCCESS;
38741da177e4SLinus Torvalds }
38751da177e4SLinus Torvalds 
38761da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
38771da177e4SLinus Torvalds {
38781da177e4SLinus Torvalds 	++num_dev_resets;
3879cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
3880cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
3881f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
3882f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
3883cbf67842SDouglas Gilbert 
3884773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3885cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
38861da177e4SLinus Torvalds 		if (devip)
3887cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
38881da177e4SLinus Torvalds 	}
38891da177e4SLinus Torvalds 	return SUCCESS;
38901da177e4SLinus Torvalds }
38911da177e4SLinus Torvalds 
3892cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3893cbf67842SDouglas Gilbert {
3894cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
3895cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3896cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
3897cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
3898cbf67842SDouglas Gilbert 	int k = 0;
3899cbf67842SDouglas Gilbert 
3900cbf67842SDouglas Gilbert 	++num_target_resets;
3901cbf67842SDouglas Gilbert 	if (!SCpnt)
3902cbf67842SDouglas Gilbert 		goto lie;
3903cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
3904cbf67842SDouglas Gilbert 	if (!sdp)
3905cbf67842SDouglas Gilbert 		goto lie;
3906773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3907cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3908cbf67842SDouglas Gilbert 	hp = sdp->host;
3909cbf67842SDouglas Gilbert 	if (!hp)
3910cbf67842SDouglas Gilbert 		goto lie;
3911cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3912cbf67842SDouglas Gilbert 	if (sdbg_host) {
3913cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
3914cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
3915cbf67842SDouglas Gilbert 				    dev_list)
3916cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
3917cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3918cbf67842SDouglas Gilbert 				++k;
3919cbf67842SDouglas Gilbert 			}
3920cbf67842SDouglas Gilbert 	}
3921773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3922cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3923cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
3924cbf67842SDouglas Gilbert lie:
3925cbf67842SDouglas Gilbert 	return SUCCESS;
3926cbf67842SDouglas Gilbert }
3927cbf67842SDouglas Gilbert 
39281da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
39291da177e4SLinus Torvalds {
39301da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
3931cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
39321da177e4SLinus Torvalds 	struct scsi_device *sdp;
39331da177e4SLinus Torvalds 	struct Scsi_Host *hp;
3934cbf67842SDouglas Gilbert 	int k = 0;
39351da177e4SLinus Torvalds 
39361da177e4SLinus Torvalds 	++num_bus_resets;
3937cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
3938cbf67842SDouglas Gilbert 		goto lie;
3939cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
3940773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3941cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3942cbf67842SDouglas Gilbert 	hp = sdp->host;
3943cbf67842SDouglas Gilbert 	if (hp) {
3944d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
39451da177e4SLinus Torvalds 		if (sdbg_host) {
3946cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
39471da177e4SLinus Torvalds 					    &sdbg_host->dev_info_list,
3948cbf67842SDouglas Gilbert 					    dev_list) {
3949cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3950cbf67842SDouglas Gilbert 				++k;
39511da177e4SLinus Torvalds 			}
39521da177e4SLinus Torvalds 		}
3953cbf67842SDouglas Gilbert 	}
3954773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3955cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3956cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
3957cbf67842SDouglas Gilbert lie:
39581da177e4SLinus Torvalds 	return SUCCESS;
39591da177e4SLinus Torvalds }
39601da177e4SLinus Torvalds 
39611da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
39621da177e4SLinus Torvalds {
39631da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
3964cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3965cbf67842SDouglas Gilbert 	int k = 0;
39661da177e4SLinus Torvalds 
39671da177e4SLinus Torvalds 	++num_host_resets;
3968773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3969cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
39701da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
39711da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3972cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
3973cbf67842SDouglas Gilbert 				    dev_list) {
3974cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3975cbf67842SDouglas Gilbert 			++k;
3976cbf67842SDouglas Gilbert 		}
39771da177e4SLinus Torvalds 	}
39781da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
39791da177e4SLinus Torvalds 	stop_all_queued();
3980773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3981cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
3982cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
39831da177e4SLinus Torvalds 	return SUCCESS;
39841da177e4SLinus Torvalds }
39851da177e4SLinus Torvalds 
3986f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
39875f2578e5SFUJITA Tomonori 				      unsigned long store_size)
39881da177e4SLinus Torvalds {
39891da177e4SLinus Torvalds 	struct partition * pp;
39901da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
39911da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
39921da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
39931da177e4SLinus Torvalds 
39941da177e4SLinus Torvalds 	/* assume partition table already zeroed */
3995773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
39961da177e4SLinus Torvalds 		return;
3997773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
3998773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
3999c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
40001da177e4SLinus Torvalds 	}
4001c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
40021da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
4003773642d9SDouglas Gilbert 			   / sdebug_num_parts;
40041da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
40051da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
4006773642d9SDouglas Gilbert 	for (k = 1; k < sdebug_num_parts; ++k)
40071da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
40081da177e4SLinus Torvalds 			    * heads_by_sects;
4009773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
4010773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
40111da177e4SLinus Torvalds 
40121da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
40131da177e4SLinus Torvalds 	ramp[511] = 0xAA;
40141da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
40151da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
40161da177e4SLinus Torvalds 		start_sec = starts[k];
40171da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
40181da177e4SLinus Torvalds 		pp->boot_ind = 0;
40191da177e4SLinus Torvalds 
40201da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
40211da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
40221da177e4SLinus Torvalds 			   / sdebug_sectors_per;
40231da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
40241da177e4SLinus Torvalds 
40251da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
40261da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
40271da177e4SLinus Torvalds 			       / sdebug_sectors_per;
40281da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
40291da177e4SLinus Torvalds 
4030150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
4031150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
40321da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
40331da177e4SLinus Torvalds 	}
40341da177e4SLinus Torvalds }
40351da177e4SLinus Torvalds 
4036c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block)
4037c4837394SDouglas Gilbert {
4038c4837394SDouglas Gilbert 	int j;
4039c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4040c4837394SDouglas Gilbert 
4041c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
4042c4837394SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)block);
4043c4837394SDouglas Gilbert }
4044c4837394SDouglas Gilbert 
4045c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
4046c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
4047c4837394SDouglas Gilbert  */
4048c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
4049c4837394SDouglas Gilbert {
4050c4837394SDouglas Gilbert 	int count, modulo;
4051c4837394SDouglas Gilbert 
4052c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
4053c4837394SDouglas Gilbert 	if (modulo < 2)
4054c4837394SDouglas Gilbert 		return;
4055c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
4056c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
4057c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
4058c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
4059c4837394SDouglas Gilbert }
4060c4837394SDouglas Gilbert 
4061c4837394SDouglas Gilbert static void clear_queue_stats(void)
4062c4837394SDouglas Gilbert {
4063c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
4064c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
4065c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
4066c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
4067c4837394SDouglas Gilbert }
4068c4837394SDouglas Gilbert 
4069c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp,
4070c4837394SDouglas Gilbert 			 struct sdebug_queued_cmd *sqcp)
4071c4837394SDouglas Gilbert {
4072c4837394SDouglas Gilbert 	if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0)
4073c4837394SDouglas Gilbert 		return;
4074c4837394SDouglas Gilbert 	sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
4075c4837394SDouglas Gilbert 	sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
4076c4837394SDouglas Gilbert 	sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
4077c4837394SDouglas Gilbert 	sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
4078c4837394SDouglas Gilbert 	sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
40797ee6d1b4SBart Van Assche 	sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
4080c4837394SDouglas Gilbert }
4081c4837394SDouglas Gilbert 
4082c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
4083c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
4084c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
4085c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
4086c4837394SDouglas Gilbert  */
4087fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
4088cbf67842SDouglas Gilbert 			 int scsi_result, int delta_jiff)
40891da177e4SLinus Torvalds {
4090cbf67842SDouglas Gilbert 	unsigned long iflags;
4091cd62b7daSDouglas Gilbert 	int k, num_in_q, qdepth, inject;
4092c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4093c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4094299b6c07STomas Winkler 	struct scsi_device *sdp;
4095a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
40961da177e4SLinus Torvalds 
4097b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
4098b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
4099f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
4100f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
41011da177e4SLinus Torvalds 	}
4102299b6c07STomas Winkler 	sdp = cmnd->device;
4103299b6c07STomas Winkler 
4104f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose && scsi_result))
4105cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4106cbf67842SDouglas Gilbert 			    __func__, scsi_result);
4107cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
4108cd62b7daSDouglas Gilbert 		goto respond_in_thread;
41091da177e4SLinus Torvalds 
4110cd62b7daSDouglas Gilbert 	/* schedule the response at a later time if resources permit */
4111c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
4112c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
4113c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
4114c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4115c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
4116c4837394SDouglas Gilbert 	}
4117cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
4118cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
4119cbf67842SDouglas Gilbert 	inject = 0;
4120f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
4121cd62b7daSDouglas Gilbert 		if (scsi_result) {
4122c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4123cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4124cd62b7daSDouglas Gilbert 		} else
4125cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4126c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
4127773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4128f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
4129cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
4130cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
4131773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
4132cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
4133cbf67842SDouglas Gilbert 			inject = 1;
4134cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
41351da177e4SLinus Torvalds 		}
4136cbf67842SDouglas Gilbert 	}
4137cbf67842SDouglas Gilbert 
4138c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
4139f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
4140c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4141cd62b7daSDouglas Gilbert 		if (scsi_result)
4142cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4143773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
4144cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4145773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
4146cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
4147cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
4148773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
4149cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
4150cbf67842SDouglas Gilbert 						    "report: host busy"));
4151cd62b7daSDouglas Gilbert 		if (scsi_result)
4152cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4153cd62b7daSDouglas Gilbert 		else
4154cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
41551da177e4SLinus Torvalds 	}
4156c4837394SDouglas Gilbert 	__set_bit(k, sqp->in_use_bm);
4157cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
4158c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
41591da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
4160c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
4161cbf67842SDouglas Gilbert 	cmnd->result = scsi_result;
4162a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
4163c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4164c4837394SDouglas Gilbert 	if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4165c4837394SDouglas Gilbert 		setup_inject(sqp, sqcp);
4166b01f6f83SDouglas Gilbert 	if (delta_jiff > 0 || sdebug_ndelay > 0) {
4167b333a819SDouglas Gilbert 		ktime_t kt;
4168cbf67842SDouglas Gilbert 
4169b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
417013f6b610SArnd Bergmann 			kt = ns_to_ktime((u64)delta_jiff * (NSEC_PER_SEC / HZ));
4171b333a819SDouglas Gilbert 		} else
41728b0e1953SThomas Gleixner 			kt = sdebug_ndelay;
4173a10bc12aSDouglas Gilbert 		if (NULL == sd_dp) {
4174a10bc12aSDouglas Gilbert 			sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
4175a10bc12aSDouglas Gilbert 			if (NULL == sd_dp)
4176cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
4177a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4178a10bc12aSDouglas Gilbert 			hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
4179c4837394SDouglas Gilbert 				     HRTIMER_MODE_REL_PINNED);
4180a10bc12aSDouglas Gilbert 			sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
4181c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4182c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4183cbf67842SDouglas Gilbert 		}
4184c4837394SDouglas Gilbert 		if (sdebug_statistics)
4185c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
4186c4837394SDouglas Gilbert 		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4187c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
4188a10bc12aSDouglas Gilbert 		if (NULL == sd_dp) {
4189a10bc12aSDouglas Gilbert 			sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC);
4190a10bc12aSDouglas Gilbert 			if (NULL == sd_dp)
4191cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
4192a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4193c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4194c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4195a10bc12aSDouglas Gilbert 			INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
4196cbf67842SDouglas Gilbert 		}
4197c4837394SDouglas Gilbert 		if (sdebug_statistics)
4198c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
4199a10bc12aSDouglas Gilbert 		schedule_work(&sd_dp->ew.work);
4200cbf67842SDouglas Gilbert 	}
4201f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4202f46eb0e9SDouglas Gilbert 		     (scsi_result == device_qfull_result)))
4203cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4204cbf67842SDouglas Gilbert 			    "%s: num_in_q=%d +1, %s%s\n", __func__,
4205cbf67842SDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""),
4206cbf67842SDouglas Gilbert 			    "status: TASK SET FULL");
42071da177e4SLinus Torvalds 	return 0;
4208cd62b7daSDouglas Gilbert 
4209cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
4210cd62b7daSDouglas Gilbert 	cmnd->result = scsi_result;
4211cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
4212cd62b7daSDouglas Gilbert 	return 0;
42131da177e4SLinus Torvalds }
4214cbf67842SDouglas Gilbert 
421523183910SDouglas Gilbert /* Note: The following macros create attribute files in the
421623183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
421723183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
421823183910SDouglas Gilbert    as it can when the corresponding attribute in the
421923183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
422023183910SDouglas Gilbert  */
4221773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4222773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
42239b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
4224773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
4225c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
4226773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4227773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
4228773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
4229773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4230773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4231773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4232773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4233773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
4234e5203cf0SHannes Reinecke module_param_string(inq_vendor, sdebug_inq_vendor_id,
4235e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR);
4236e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
4237e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR);
4238e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
4239e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR);
4240773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4241773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4242773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4243773642d9SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4244773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4245773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4246773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4247773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4248773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4249773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4250773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4251773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4252773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4253773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4254773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
425586e6828aSLukas Herbolt module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
4256773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4257773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4258773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4259773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
4260c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
4261773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
4262c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
4263773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4264773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4265773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4266773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4267773642d9SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
426809ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
4269773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
427023183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
4271773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
42725b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
42731da177e4SLinus Torvalds 
42741da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
42751da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
42761da177e4SLinus Torvalds MODULE_LICENSE("GPL");
4277b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
42781da177e4SLinus Torvalds 
42791da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
42805b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
42819b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
42820759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
4283cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
4284c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
42855b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
42865b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
4287c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
4288beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
428923183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
42905b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
4291185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
4292e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
4293e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
42949b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
42959b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
42965b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
42975b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
42985b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
4299760f3b03SDouglas Gilbert MODULE_PARM_DESC(lbprz,
4300760f3b03SDouglas Gilbert 	"on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
43015b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
4302c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
4303cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4304cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
4305c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
430678d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
43071da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
4308c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
430932c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
43106f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
43115b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
431286e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
43131da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
4314d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
4315760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
4316ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
4317c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
4318c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
4319c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
43205b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
43215b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
43226014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
43236014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
432409ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
432509ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
4326c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
43275b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
43285b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
43291da177e4SLinus Torvalds 
4330760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
4331760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
43321da177e4SLinus Torvalds 
43331da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp)
43341da177e4SLinus Torvalds {
4335c4837394SDouglas Gilbert 	int k;
4336c4837394SDouglas Gilbert 
4337760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4338760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
4339760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
4340c4837394SDouglas Gilbert 		return sdebug_info;
4341760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4342760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4343760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
4344760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
43451da177e4SLinus Torvalds 	return sdebug_info;
43461da177e4SLinus Torvalds }
43471da177e4SLinus Torvalds 
4348cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
4349fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4350fd32119bSDouglas Gilbert 				 int length)
43511da177e4SLinus Torvalds {
43521da177e4SLinus Torvalds 	char arr[16];
4353c8ed555aSAl Viro 	int opts;
43541da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
43551da177e4SLinus Torvalds 
43561da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
43571da177e4SLinus Torvalds 		return -EACCES;
43581da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
43591da177e4SLinus Torvalds 	arr[minLen] = '\0';
4360c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
43611da177e4SLinus Torvalds 		return -EINVAL;
4362773642d9SDouglas Gilbert 	sdebug_opts = opts;
4363773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4364773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4365773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
4366c4837394SDouglas Gilbert 		tweak_cmnd_count();
43671da177e4SLinus Torvalds 	return length;
43681da177e4SLinus Torvalds }
4369c8ed555aSAl Viro 
4370cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4371cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
4372cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
4373c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4374c8ed555aSAl Viro {
4375c4837394SDouglas Gilbert 	int f, j, l;
4376c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4377cbf67842SDouglas Gilbert 
4378c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4379c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
4380c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4381c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4382c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
4383c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4384c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4385c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
4386c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4387c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4388c4837394SDouglas Gilbert 		   num_aborts);
4389c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4390c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
4391c4837394SDouglas Gilbert 		   num_host_resets);
4392c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4393c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
4394c4837394SDouglas Gilbert 	seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n",
4395c4837394SDouglas Gilbert 		   TICK_NSEC / 1000, "statistics", sdebug_statistics,
4396c4837394SDouglas Gilbert 		   sdebug_mq_active);
4397c4837394SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4398c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
4399c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
4400c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
4401c4837394SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf));
4402cbf67842SDouglas Gilbert 
4403c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
4404c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4405c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
4406c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4407773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
4408c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4409c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
4410c4837394SDouglas Gilbert 				   "first,last bits", f, l);
4411c4837394SDouglas Gilbert 		}
4412cbf67842SDouglas Gilbert 	}
4413c8ed555aSAl Viro 	return 0;
44141da177e4SLinus Torvalds }
44151da177e4SLinus Torvalds 
441682069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
44171da177e4SLinus Torvalds {
4418c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
44191da177e4SLinus Torvalds }
4420c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4421c4837394SDouglas Gilbert  * of delay is jiffies.
4422c4837394SDouglas Gilbert  */
442382069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
442482069379SAkinobu Mita 			   size_t count)
44251da177e4SLinus Torvalds {
4426c2206098SDouglas Gilbert 	int jdelay, res;
44271da177e4SLinus Torvalds 
4428b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
4429cbf67842SDouglas Gilbert 		res = count;
4430c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
4431c4837394SDouglas Gilbert 			int j, k;
4432c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4433cbf67842SDouglas Gilbert 
4434c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4435c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4436c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4437c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4438c4837394SDouglas Gilbert 						   sdebug_max_queue);
4439c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4440c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4441c4837394SDouglas Gilbert 					break;
4442c4837394SDouglas Gilbert 				}
4443c4837394SDouglas Gilbert 			}
4444c4837394SDouglas Gilbert 			if (res > 0) {
4445a10bc12aSDouglas Gilbert 				/* make sure sdebug_defer instances get
4446a10bc12aSDouglas Gilbert 				 * re-allocated for new delay variant */
4447a10bc12aSDouglas Gilbert 				free_all_queued();
4448c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
4449773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
44501da177e4SLinus Torvalds 			}
4451c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4452cbf67842SDouglas Gilbert 		}
4453cbf67842SDouglas Gilbert 		return res;
44541da177e4SLinus Torvalds 	}
44551da177e4SLinus Torvalds 	return -EINVAL;
44561da177e4SLinus Torvalds }
445782069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
44581da177e4SLinus Torvalds 
4459cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4460cbf67842SDouglas Gilbert {
4461773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
4462cbf67842SDouglas Gilbert }
4463cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
4464c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
4465cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
4466cbf67842SDouglas Gilbert 			    size_t count)
4467cbf67842SDouglas Gilbert {
4468c4837394SDouglas Gilbert 	int ndelay, res;
4469cbf67842SDouglas Gilbert 
4470cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4471c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
4472cbf67842SDouglas Gilbert 		res = count;
4473773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
4474c4837394SDouglas Gilbert 			int j, k;
4475c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4476c4837394SDouglas Gilbert 
4477c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4478c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4479c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4480c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4481c4837394SDouglas Gilbert 						   sdebug_max_queue);
4482c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4483c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4484c4837394SDouglas Gilbert 					break;
4485c4837394SDouglas Gilbert 				}
4486c4837394SDouglas Gilbert 			}
4487c4837394SDouglas Gilbert 			if (res > 0) {
4488a10bc12aSDouglas Gilbert 				/* make sure sdebug_defer instances get
4489a10bc12aSDouglas Gilbert 				 * re-allocated for new delay variant */
4490a10bc12aSDouglas Gilbert 				free_all_queued();
4491773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
4492c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
4493c2206098SDouglas Gilbert 							: DEF_JDELAY;
4494cbf67842SDouglas Gilbert 			}
4495c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4496cbf67842SDouglas Gilbert 		}
4497cbf67842SDouglas Gilbert 		return res;
4498cbf67842SDouglas Gilbert 	}
4499cbf67842SDouglas Gilbert 	return -EINVAL;
4500cbf67842SDouglas Gilbert }
4501cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
4502cbf67842SDouglas Gilbert 
450382069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
45041da177e4SLinus Torvalds {
4505773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
45061da177e4SLinus Torvalds }
45071da177e4SLinus Torvalds 
450882069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
450982069379SAkinobu Mita 			  size_t count)
45101da177e4SLinus Torvalds {
45111da177e4SLinus Torvalds 	int opts;
45121da177e4SLinus Torvalds 	char work[20];
45131da177e4SLinus Torvalds 
45149a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
45159a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
45169a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
45171da177e4SLinus Torvalds 				goto opts_done;
45181da177e4SLinus Torvalds 		} else {
45199a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
45201da177e4SLinus Torvalds 				goto opts_done;
45211da177e4SLinus Torvalds 		}
45221da177e4SLinus Torvalds 	}
45231da177e4SLinus Torvalds 	return -EINVAL;
45241da177e4SLinus Torvalds opts_done:
4525773642d9SDouglas Gilbert 	sdebug_opts = opts;
4526773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4527773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4528c4837394SDouglas Gilbert 	tweak_cmnd_count();
45291da177e4SLinus Torvalds 	return count;
45301da177e4SLinus Torvalds }
453182069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
45321da177e4SLinus Torvalds 
453382069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
45341da177e4SLinus Torvalds {
4535773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
45361da177e4SLinus Torvalds }
453782069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
453882069379SAkinobu Mita 			   size_t count)
45391da177e4SLinus Torvalds {
45401da177e4SLinus Torvalds 	int n;
45411da177e4SLinus Torvalds 
45421da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4543773642d9SDouglas Gilbert 		sdebug_ptype = n;
45441da177e4SLinus Torvalds 		return count;
45451da177e4SLinus Torvalds 	}
45461da177e4SLinus Torvalds 	return -EINVAL;
45471da177e4SLinus Torvalds }
454882069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
45491da177e4SLinus Torvalds 
455082069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
45511da177e4SLinus Torvalds {
4552773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
45531da177e4SLinus Torvalds }
455482069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
455582069379SAkinobu Mita 			    size_t count)
45561da177e4SLinus Torvalds {
45571da177e4SLinus Torvalds 	int n;
45581da177e4SLinus Torvalds 
45591da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4560773642d9SDouglas Gilbert 		sdebug_dsense = n;
45611da177e4SLinus Torvalds 		return count;
45621da177e4SLinus Torvalds 	}
45631da177e4SLinus Torvalds 	return -EINVAL;
45641da177e4SLinus Torvalds }
456582069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
45661da177e4SLinus Torvalds 
456782069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
456823183910SDouglas Gilbert {
4569773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
457023183910SDouglas Gilbert }
457182069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
457282069379SAkinobu Mita 			     size_t count)
457323183910SDouglas Gilbert {
457423183910SDouglas Gilbert 	int n;
457523183910SDouglas Gilbert 
457623183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4577cbf67842SDouglas Gilbert 		n = (n > 0);
4578773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
4579773642d9SDouglas Gilbert 		if (sdebug_fake_rw != n) {
4580cbf67842SDouglas Gilbert 			if ((0 == n) && (NULL == fake_storep)) {
4581cbf67842SDouglas Gilbert 				unsigned long sz =
4582773642d9SDouglas Gilbert 					(unsigned long)sdebug_dev_size_mb *
4583cbf67842SDouglas Gilbert 					1048576;
4584cbf67842SDouglas Gilbert 
4585cbf67842SDouglas Gilbert 				fake_storep = vmalloc(sz);
4586cbf67842SDouglas Gilbert 				if (NULL == fake_storep) {
4587c1287970STomas Winkler 					pr_err("out of memory, 9\n");
4588cbf67842SDouglas Gilbert 					return -ENOMEM;
4589cbf67842SDouglas Gilbert 				}
4590cbf67842SDouglas Gilbert 				memset(fake_storep, 0, sz);
4591cbf67842SDouglas Gilbert 			}
4592773642d9SDouglas Gilbert 			sdebug_fake_rw = n;
4593cbf67842SDouglas Gilbert 		}
459423183910SDouglas Gilbert 		return count;
459523183910SDouglas Gilbert 	}
459623183910SDouglas Gilbert 	return -EINVAL;
459723183910SDouglas Gilbert }
459882069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
459923183910SDouglas Gilbert 
460082069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
4601c65b1445SDouglas Gilbert {
4602773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
4603c65b1445SDouglas Gilbert }
460482069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
460582069379SAkinobu Mita 			      size_t count)
4606c65b1445SDouglas Gilbert {
4607c65b1445SDouglas Gilbert 	int n;
4608c65b1445SDouglas Gilbert 
4609c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4610773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
4611c65b1445SDouglas Gilbert 		return count;
4612c65b1445SDouglas Gilbert 	}
4613c65b1445SDouglas Gilbert 	return -EINVAL;
4614c65b1445SDouglas Gilbert }
461582069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
4616c65b1445SDouglas Gilbert 
461782069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
46181da177e4SLinus Torvalds {
4619773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
46201da177e4SLinus Torvalds }
462182069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
462282069379SAkinobu Mita 			      size_t count)
46231da177e4SLinus Torvalds {
46241da177e4SLinus Torvalds 	int n;
46251da177e4SLinus Torvalds 
46261da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4627773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
46281da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
46291da177e4SLinus Torvalds 		return count;
46301da177e4SLinus Torvalds 	}
46311da177e4SLinus Torvalds 	return -EINVAL;
46321da177e4SLinus Torvalds }
463382069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
46341da177e4SLinus Torvalds 
463582069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
46361da177e4SLinus Torvalds {
4637773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
46381da177e4SLinus Torvalds }
463982069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
46401da177e4SLinus Torvalds 
464182069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
46421da177e4SLinus Torvalds {
4643773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
46441da177e4SLinus Torvalds }
464582069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
46461da177e4SLinus Torvalds 
464782069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
46481da177e4SLinus Torvalds {
4649773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
46501da177e4SLinus Torvalds }
465182069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
465282069379SAkinobu Mita 			       size_t count)
46531da177e4SLinus Torvalds {
46541da177e4SLinus Torvalds 	int nth;
46551da177e4SLinus Torvalds 
46561da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
4657773642d9SDouglas Gilbert 		sdebug_every_nth = nth;
4658c4837394SDouglas Gilbert 		if (nth && !sdebug_statistics) {
4659c4837394SDouglas Gilbert 			pr_info("every_nth needs statistics=1, set it\n");
4660c4837394SDouglas Gilbert 			sdebug_statistics = true;
4661c4837394SDouglas Gilbert 		}
4662c4837394SDouglas Gilbert 		tweak_cmnd_count();
46631da177e4SLinus Torvalds 		return count;
46641da177e4SLinus Torvalds 	}
46651da177e4SLinus Torvalds 	return -EINVAL;
46661da177e4SLinus Torvalds }
466782069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
46681da177e4SLinus Torvalds 
466982069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
46701da177e4SLinus Torvalds {
4671773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
46721da177e4SLinus Torvalds }
467382069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
467482069379SAkinobu Mita 			      size_t count)
46751da177e4SLinus Torvalds {
46761da177e4SLinus Torvalds 	int n;
467719c8ead7SEwan D. Milne 	bool changed;
46781da177e4SLinus Torvalds 
46791da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
46808d039e22SDouglas Gilbert 		if (n > 256) {
46818d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
46828d039e22SDouglas Gilbert 			return -EINVAL;
46838d039e22SDouglas Gilbert 		}
4684773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
4685773642d9SDouglas Gilbert 		sdebug_max_luns = n;
46861da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
4687773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
468819c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
468919c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
469019c8ead7SEwan D. Milne 
469119c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
469219c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
469319c8ead7SEwan D. Milne 					    host_list) {
469419c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
469519c8ead7SEwan D. Milne 						    dev_list) {
469619c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
469719c8ead7SEwan D. Milne 						dp->uas_bm);
469819c8ead7SEwan D. Milne 				}
469919c8ead7SEwan D. Milne 			}
470019c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
470119c8ead7SEwan D. Milne 		}
47021da177e4SLinus Torvalds 		return count;
47031da177e4SLinus Torvalds 	}
47041da177e4SLinus Torvalds 	return -EINVAL;
47051da177e4SLinus Torvalds }
470682069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
47071da177e4SLinus Torvalds 
470882069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
470978d4e5a0SDouglas Gilbert {
4710773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
471178d4e5a0SDouglas Gilbert }
4712cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
4713cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
471482069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
471582069379SAkinobu Mita 			       size_t count)
471678d4e5a0SDouglas Gilbert {
4717c4837394SDouglas Gilbert 	int j, n, k, a;
4718c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
471978d4e5a0SDouglas Gilbert 
472078d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
4721c4837394SDouglas Gilbert 	    (n <= SDEBUG_CANQUEUE)) {
4722c4837394SDouglas Gilbert 		block_unblock_all_queues(true);
4723c4837394SDouglas Gilbert 		k = 0;
4724c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4725c4837394SDouglas Gilbert 		     ++j, ++sqp) {
4726c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4727c4837394SDouglas Gilbert 			if (a > k)
4728c4837394SDouglas Gilbert 				k = a;
4729c4837394SDouglas Gilbert 		}
4730773642d9SDouglas Gilbert 		sdebug_max_queue = n;
4731c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
4732cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4733cbf67842SDouglas Gilbert 		else if (k >= n)
4734cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4735cbf67842SDouglas Gilbert 		else
4736cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4737c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
473878d4e5a0SDouglas Gilbert 		return count;
473978d4e5a0SDouglas Gilbert 	}
474078d4e5a0SDouglas Gilbert 	return -EINVAL;
474178d4e5a0SDouglas Gilbert }
474282069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
474378d4e5a0SDouglas Gilbert 
474482069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
474578d4e5a0SDouglas Gilbert {
4746773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
474778d4e5a0SDouglas Gilbert }
474882069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
474978d4e5a0SDouglas Gilbert 
475082069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
47511da177e4SLinus Torvalds {
4752773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
47531da177e4SLinus Torvalds }
475482069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
47551da177e4SLinus Torvalds 
475682069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
4757c65b1445SDouglas Gilbert {
4758773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
4759c65b1445SDouglas Gilbert }
476082069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
476182069379SAkinobu Mita 				size_t count)
4762c65b1445SDouglas Gilbert {
4763c65b1445SDouglas Gilbert 	int n;
47640d01c5dfSDouglas Gilbert 	bool changed;
4765c65b1445SDouglas Gilbert 
4766c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4767773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
4768773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
476928898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
47700d01c5dfSDouglas Gilbert 		if (changed) {
47710d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
47720d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
477328898873SFUJITA Tomonori 
47744bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
47750d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
47760d01c5dfSDouglas Gilbert 					    host_list) {
47770d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
47780d01c5dfSDouglas Gilbert 						    dev_list) {
47790d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
47800d01c5dfSDouglas Gilbert 						dp->uas_bm);
47810d01c5dfSDouglas Gilbert 				}
47820d01c5dfSDouglas Gilbert 			}
47834bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
47840d01c5dfSDouglas Gilbert 		}
4785c65b1445SDouglas Gilbert 		return count;
4786c65b1445SDouglas Gilbert 	}
4787c65b1445SDouglas Gilbert 	return -EINVAL;
4788c65b1445SDouglas Gilbert }
478982069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
4790c65b1445SDouglas Gilbert 
479182069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
47921da177e4SLinus Torvalds {
4793773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
47941da177e4SLinus Torvalds }
47951da177e4SLinus Torvalds 
4796fd32119bSDouglas Gilbert static int sdebug_add_adapter(void);
4797fd32119bSDouglas Gilbert static void sdebug_remove_adapter(void);
4798fd32119bSDouglas Gilbert 
479982069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
480082069379SAkinobu Mita 			      size_t count)
48011da177e4SLinus Torvalds {
48021da177e4SLinus Torvalds 	int delta_hosts;
48031da177e4SLinus Torvalds 
4804f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
48051da177e4SLinus Torvalds 		return -EINVAL;
48061da177e4SLinus Torvalds 	if (delta_hosts > 0) {
48071da177e4SLinus Torvalds 		do {
48081da177e4SLinus Torvalds 			sdebug_add_adapter();
48091da177e4SLinus Torvalds 		} while (--delta_hosts);
48101da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
48111da177e4SLinus Torvalds 		do {
48121da177e4SLinus Torvalds 			sdebug_remove_adapter();
48131da177e4SLinus Torvalds 		} while (++delta_hosts);
48141da177e4SLinus Torvalds 	}
48151da177e4SLinus Torvalds 	return count;
48161da177e4SLinus Torvalds }
481782069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
48181da177e4SLinus Torvalds 
481982069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
482023183910SDouglas Gilbert {
4821773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
482223183910SDouglas Gilbert }
482382069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
482482069379SAkinobu Mita 				    size_t count)
482523183910SDouglas Gilbert {
482623183910SDouglas Gilbert 	int n;
482723183910SDouglas Gilbert 
482823183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4829773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
483023183910SDouglas Gilbert 		return count;
483123183910SDouglas Gilbert 	}
483223183910SDouglas Gilbert 	return -EINVAL;
483323183910SDouglas Gilbert }
483482069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
483523183910SDouglas Gilbert 
4836c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
4837c4837394SDouglas Gilbert {
4838c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
4839c4837394SDouglas Gilbert }
4840c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
4841c4837394SDouglas Gilbert 				size_t count)
4842c4837394SDouglas Gilbert {
4843c4837394SDouglas Gilbert 	int n;
4844c4837394SDouglas Gilbert 
4845c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
4846c4837394SDouglas Gilbert 		if (n > 0)
4847c4837394SDouglas Gilbert 			sdebug_statistics = true;
4848c4837394SDouglas Gilbert 		else {
4849c4837394SDouglas Gilbert 			clear_queue_stats();
4850c4837394SDouglas Gilbert 			sdebug_statistics = false;
4851c4837394SDouglas Gilbert 		}
4852c4837394SDouglas Gilbert 		return count;
4853c4837394SDouglas Gilbert 	}
4854c4837394SDouglas Gilbert 	return -EINVAL;
4855c4837394SDouglas Gilbert }
4856c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
4857c4837394SDouglas Gilbert 
485882069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
4859597136abSMartin K. Petersen {
4860773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
4861597136abSMartin K. Petersen }
486282069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
4863597136abSMartin K. Petersen 
4864c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
4865c4837394SDouglas Gilbert {
4866c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
4867c4837394SDouglas Gilbert }
4868c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
4869c4837394SDouglas Gilbert 
487082069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
4871c6a44287SMartin K. Petersen {
4872773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
4873c6a44287SMartin K. Petersen }
487482069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
4875c6a44287SMartin K. Petersen 
487682069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
4877c6a44287SMartin K. Petersen {
4878773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
4879c6a44287SMartin K. Petersen }
488082069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
4881c6a44287SMartin K. Petersen 
488282069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
4883c6a44287SMartin K. Petersen {
4884773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
4885c6a44287SMartin K. Petersen }
488682069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
4887c6a44287SMartin K. Petersen 
488882069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
4889c6a44287SMartin K. Petersen {
4890773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
4891c6a44287SMartin K. Petersen }
489282069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
4893c6a44287SMartin K. Petersen 
489482069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
489544d92694SMartin K. Petersen {
489644d92694SMartin K. Petersen 	ssize_t count;
489744d92694SMartin K. Petersen 
48985b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
489944d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
490044d92694SMartin K. Petersen 				 sdebug_store_sectors);
490144d92694SMartin K. Petersen 
4902c7badc90STejun Heo 	count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
4903c7badc90STejun Heo 			  (int)map_size, map_storep);
490444d92694SMartin K. Petersen 	buf[count++] = '\n';
4905c7badc90STejun Heo 	buf[count] = '\0';
490644d92694SMartin K. Petersen 
490744d92694SMartin K. Petersen 	return count;
490844d92694SMartin K. Petersen }
490982069379SAkinobu Mita static DRIVER_ATTR_RO(map);
491044d92694SMartin K. Petersen 
491182069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
4912d986788bSMartin Pitt {
4913773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
4914d986788bSMartin Pitt }
491582069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
491682069379SAkinobu Mita 			       size_t count)
4917d986788bSMartin Pitt {
4918d986788bSMartin Pitt 	int n;
4919d986788bSMartin Pitt 
4920d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4921773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
4922d986788bSMartin Pitt 		return count;
4923d986788bSMartin Pitt 	}
4924d986788bSMartin Pitt 	return -EINVAL;
4925d986788bSMartin Pitt }
492682069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
4927d986788bSMartin Pitt 
4928cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4929cbf67842SDouglas Gilbert {
4930773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
4931cbf67842SDouglas Gilbert }
4932185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
4933cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4934cbf67842SDouglas Gilbert 			       size_t count)
4935cbf67842SDouglas Gilbert {
4936185dd232SDouglas Gilbert 	int n;
4937cbf67842SDouglas Gilbert 
4938cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4939185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
4940185dd232SDouglas Gilbert 		return count;
4941cbf67842SDouglas Gilbert 	}
4942cbf67842SDouglas Gilbert 	return -EINVAL;
4943cbf67842SDouglas Gilbert }
4944cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
4945cbf67842SDouglas Gilbert 
4946c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
4947c2248fc9SDouglas Gilbert {
4948773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
4949c2248fc9SDouglas Gilbert }
4950c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4951c2248fc9SDouglas Gilbert 			    size_t count)
4952c2248fc9SDouglas Gilbert {
4953c2248fc9SDouglas Gilbert 	int n;
4954c2248fc9SDouglas Gilbert 
4955c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4956773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
4957c2248fc9SDouglas Gilbert 		return count;
4958c2248fc9SDouglas Gilbert 	}
4959c2248fc9SDouglas Gilbert 	return -EINVAL;
4960c2248fc9SDouglas Gilbert }
4961c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
4962c2248fc9SDouglas Gilbert 
496309ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
496409ba24c1SDouglas Gilbert {
496509ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
496609ba24c1SDouglas Gilbert }
496709ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
496809ba24c1SDouglas Gilbert 
49699b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
49709b760fd8SDouglas Gilbert {
49719b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
49729b760fd8SDouglas Gilbert }
49739b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
49749b760fd8SDouglas Gilbert 			     size_t count)
49759b760fd8SDouglas Gilbert {
49769b760fd8SDouglas Gilbert 	int ret, n;
49779b760fd8SDouglas Gilbert 
49789b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
49799b760fd8SDouglas Gilbert 	if (ret)
49809b760fd8SDouglas Gilbert 		return ret;
49819b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
49829b760fd8SDouglas Gilbert 	all_config_cdb_len();
49839b760fd8SDouglas Gilbert 	return count;
49849b760fd8SDouglas Gilbert }
49859b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
49869b760fd8SDouglas Gilbert 
4987cbf67842SDouglas Gilbert 
498882069379SAkinobu Mita /* Note: The following array creates attribute files in the
498923183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
499023183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
499123183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
499223183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
499323183910SDouglas Gilbert  */
49946ecaff7fSRandy Dunlap 
499582069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
499682069379SAkinobu Mita 	&driver_attr_delay.attr,
499782069379SAkinobu Mita 	&driver_attr_opts.attr,
499882069379SAkinobu Mita 	&driver_attr_ptype.attr,
499982069379SAkinobu Mita 	&driver_attr_dsense.attr,
500082069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
500182069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
500282069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
500382069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
500482069379SAkinobu Mita 	&driver_attr_num_parts.attr,
500582069379SAkinobu Mita 	&driver_attr_every_nth.attr,
500682069379SAkinobu Mita 	&driver_attr_max_luns.attr,
500782069379SAkinobu Mita 	&driver_attr_max_queue.attr,
500882069379SAkinobu Mita 	&driver_attr_no_uld.attr,
500982069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
501082069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
501182069379SAkinobu Mita 	&driver_attr_add_host.attr,
501282069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
501382069379SAkinobu Mita 	&driver_attr_sector_size.attr,
5014c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
5015c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
501682069379SAkinobu Mita 	&driver_attr_dix.attr,
501782069379SAkinobu Mita 	&driver_attr_dif.attr,
501882069379SAkinobu Mita 	&driver_attr_guard.attr,
501982069379SAkinobu Mita 	&driver_attr_ato.attr,
502082069379SAkinobu Mita 	&driver_attr_map.attr,
502182069379SAkinobu Mita 	&driver_attr_removable.attr,
5022cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
5023cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
5024c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
502509ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
50269b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
502782069379SAkinobu Mita 	NULL,
502882069379SAkinobu Mita };
502982069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
50301da177e4SLinus Torvalds 
503111ddcecaSAkinobu Mita static struct device *pseudo_primary;
50328dea0d02SFUJITA Tomonori 
50331da177e4SLinus Torvalds static int __init scsi_debug_init(void)
50341da177e4SLinus Torvalds {
50355f2578e5SFUJITA Tomonori 	unsigned long sz;
50361da177e4SLinus Torvalds 	int host_to_add;
50371da177e4SLinus Torvalds 	int k;
50386ecaff7fSRandy Dunlap 	int ret;
50391da177e4SLinus Torvalds 
5040cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
5041cbf67842SDouglas Gilbert 
5042773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
5043c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
5044773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
5045773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
5046c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
5047cbf67842SDouglas Gilbert 
5048773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
5049597136abSMartin K. Petersen 	case  512:
5050597136abSMartin K. Petersen 	case 1024:
5051597136abSMartin K. Petersen 	case 2048:
5052597136abSMartin K. Petersen 	case 4096:
5053597136abSMartin K. Petersen 		break;
5054597136abSMartin K. Petersen 	default:
5055773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
5056597136abSMartin K. Petersen 		return -EINVAL;
5057597136abSMartin K. Petersen 	}
5058597136abSMartin K. Petersen 
5059773642d9SDouglas Gilbert 	switch (sdebug_dif) {
50608475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
5061f46eb0e9SDouglas Gilbert 		break;
50628475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
50638475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
50648475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
5065f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
5066c6a44287SMartin K. Petersen 		break;
5067c6a44287SMartin K. Petersen 
5068c6a44287SMartin K. Petersen 	default:
5069c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
5070c6a44287SMartin K. Petersen 		return -EINVAL;
5071c6a44287SMartin K. Petersen 	}
5072c6a44287SMartin K. Petersen 
5073773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
5074c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
5075c6a44287SMartin K. Petersen 		return -EINVAL;
5076c6a44287SMartin K. Petersen 	}
5077c6a44287SMartin K. Petersen 
5078773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
5079c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
5080c6a44287SMartin K. Petersen 		return -EINVAL;
5081c6a44287SMartin K. Petersen 	}
5082c6a44287SMartin K. Petersen 
5083773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
5084773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
5085ea61fca5SMartin K. Petersen 		return -EINVAL;
5086ea61fca5SMartin K. Petersen 	}
50878d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
50888d039e22SDouglas Gilbert 		pr_warn("max_luns can be no more than 256, use default\n");
50898d039e22SDouglas Gilbert 		sdebug_max_luns = DEF_MAX_LUNS;
50908d039e22SDouglas Gilbert 	}
5091ea61fca5SMartin K. Petersen 
5092773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
5093773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
5094ea61fca5SMartin K. Petersen 		return -EINVAL;
5095ea61fca5SMartin K. Petersen 	}
5096ea61fca5SMartin K. Petersen 
5097c4837394SDouglas Gilbert 	if (submit_queues < 1) {
5098c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
5099c4837394SDouglas Gilbert 		return -EINVAL;
5100c4837394SDouglas Gilbert 	}
5101c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
5102c4837394SDouglas Gilbert 			       GFP_KERNEL);
5103c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
5104c4837394SDouglas Gilbert 		return -ENOMEM;
5105c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
5106c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
5107c4837394SDouglas Gilbert 
5108773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
5109773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
5110773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
5111773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
511228898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
51131da177e4SLinus Torvalds 
51141da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
51151da177e4SLinus Torvalds 	sdebug_heads = 8;
51161da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
5117773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
51181da177e4SLinus Torvalds 		sdebug_heads = 64;
5119773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
5120fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
51211da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
51221da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
51231da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
51241da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
51251da177e4SLinus Torvalds 		sdebug_heads = 255;
51261da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
51271da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
51281da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
51291da177e4SLinus Torvalds 	}
51301da177e4SLinus Torvalds 
5131b01f6f83SDouglas Gilbert 	if (sdebug_fake_rw == 0) {
51321da177e4SLinus Torvalds 		fake_storep = vmalloc(sz);
51331da177e4SLinus Torvalds 		if (NULL == fake_storep) {
5134c1287970STomas Winkler 			pr_err("out of memory, 1\n");
5135c4837394SDouglas Gilbert 			ret = -ENOMEM;
5136c4837394SDouglas Gilbert 			goto free_q_arr;
51371da177e4SLinus Torvalds 		}
51381da177e4SLinus Torvalds 		memset(fake_storep, 0, sz);
5139773642d9SDouglas Gilbert 		if (sdebug_num_parts > 0)
5140f58b0efbSFUJITA Tomonori 			sdebug_build_parts(fake_storep, sz);
5141cbf67842SDouglas Gilbert 	}
51421da177e4SLinus Torvalds 
5143773642d9SDouglas Gilbert 	if (sdebug_dix) {
5144c6a44287SMartin K. Petersen 		int dif_size;
5145c6a44287SMartin K. Petersen 
51466ebf105cSChristoph Hellwig 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
5147c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
5148c6a44287SMartin K. Petersen 
5149c1287970STomas Winkler 		pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
5150c6a44287SMartin K. Petersen 
5151c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
5152c1287970STomas Winkler 			pr_err("out of mem. (DIX)\n");
5153c6a44287SMartin K. Petersen 			ret = -ENOMEM;
5154c6a44287SMartin K. Petersen 			goto free_vm;
5155c6a44287SMartin K. Petersen 		}
5156c6a44287SMartin K. Petersen 
5157c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
5158c6a44287SMartin K. Petersen 	}
5159c6a44287SMartin K. Petersen 
51605b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
51615b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
5162773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
5163773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
51646014759cSMartin K. Petersen 
5165773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
5166773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
51676014759cSMartin K. Petersen 
5168773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
5169773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
51706014759cSMartin K. Petersen 
5171773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
5172773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
5173773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
5174c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
5175c4837394SDouglas Gilbert 			ret = -EINVAL;
5176c4837394SDouglas Gilbert 			goto free_vm;
517744d92694SMartin K. Petersen 		}
517844d92694SMartin K. Petersen 
5179b90ebc3dSAkinobu Mita 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
5180b90ebc3dSAkinobu Mita 		map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
518144d92694SMartin K. Petersen 
5182c1287970STomas Winkler 		pr_info("%lu provisioning blocks\n", map_size);
518344d92694SMartin K. Petersen 
518444d92694SMartin K. Petersen 		if (map_storep == NULL) {
5185c1287970STomas Winkler 			pr_err("out of mem. (MAP)\n");
518644d92694SMartin K. Petersen 			ret = -ENOMEM;
518744d92694SMartin K. Petersen 			goto free_vm;
518844d92694SMartin K. Petersen 		}
518944d92694SMartin K. Petersen 
5190b90ebc3dSAkinobu Mita 		bitmap_zero(map_storep, map_size);
519144d92694SMartin K. Petersen 
519244d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
5193773642d9SDouglas Gilbert 		if (sdebug_num_parts)
519444d92694SMartin K. Petersen 			map_region(0, 2);
519544d92694SMartin K. Petersen 	}
519644d92694SMartin K. Petersen 
51979b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
51989b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
5199c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
52009b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
52016ecaff7fSRandy Dunlap 		goto free_vm;
52026ecaff7fSRandy Dunlap 	}
52036ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
52046ecaff7fSRandy Dunlap 	if (ret < 0) {
5205c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
52066ecaff7fSRandy Dunlap 		goto dev_unreg;
52076ecaff7fSRandy Dunlap 	}
52086ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
52096ecaff7fSRandy Dunlap 	if (ret < 0) {
5210c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
52116ecaff7fSRandy Dunlap 		goto bus_unreg;
52126ecaff7fSRandy Dunlap 	}
52131da177e4SLinus Torvalds 
5214773642d9SDouglas Gilbert 	host_to_add = sdebug_add_host;
5215773642d9SDouglas Gilbert 	sdebug_add_host = 0;
52161da177e4SLinus Torvalds 
52171da177e4SLinus Torvalds 	for (k = 0; k < host_to_add; k++) {
52181da177e4SLinus Torvalds 		if (sdebug_add_adapter()) {
5219c1287970STomas Winkler 			pr_err("sdebug_add_adapter failed k=%d\n", k);
52201da177e4SLinus Torvalds 			break;
52211da177e4SLinus Torvalds 		}
52221da177e4SLinus Torvalds 	}
52231da177e4SLinus Torvalds 
5224773642d9SDouglas Gilbert 	if (sdebug_verbose)
5225773642d9SDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_add_host);
5226c1287970STomas Winkler 
52271da177e4SLinus Torvalds 	return 0;
52286ecaff7fSRandy Dunlap 
52296ecaff7fSRandy Dunlap bus_unreg:
52306ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
52316ecaff7fSRandy Dunlap dev_unreg:
52329b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
52336ecaff7fSRandy Dunlap free_vm:
523444d92694SMartin K. Petersen 	vfree(map_storep);
5235c6a44287SMartin K. Petersen 	vfree(dif_storep);
52366ecaff7fSRandy Dunlap 	vfree(fake_storep);
5237c4837394SDouglas Gilbert free_q_arr:
5238c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
52396ecaff7fSRandy Dunlap 	return ret;
52401da177e4SLinus Torvalds }
52411da177e4SLinus Torvalds 
52421da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
52431da177e4SLinus Torvalds {
5244773642d9SDouglas Gilbert 	int k = sdebug_add_host;
52451da177e4SLinus Torvalds 
52461da177e4SLinus Torvalds 	stop_all_queued();
5247cbf67842SDouglas Gilbert 	free_all_queued();
52481da177e4SLinus Torvalds 	for (; k; k--)
52491da177e4SLinus Torvalds 		sdebug_remove_adapter();
52501da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
52511da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
52529b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
52531da177e4SLinus Torvalds 
52544d2b496fSEwan D. Milne 	vfree(map_storep);
5255c6a44287SMartin K. Petersen 	vfree(dif_storep);
52561da177e4SLinus Torvalds 	vfree(fake_storep);
5257c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
52581da177e4SLinus Torvalds }
52591da177e4SLinus Torvalds 
52601da177e4SLinus Torvalds device_initcall(scsi_debug_init);
52611da177e4SLinus Torvalds module_exit(scsi_debug_exit);
52621da177e4SLinus Torvalds 
52631da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev)
52641da177e4SLinus Torvalds {
52651da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
52661da177e4SLinus Torvalds 
52671da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
52681da177e4SLinus Torvalds 	kfree(sdbg_host);
52691da177e4SLinus Torvalds }
52701da177e4SLinus Torvalds 
52711da177e4SLinus Torvalds static int sdebug_add_adapter(void)
52721da177e4SLinus Torvalds {
52731da177e4SLinus Torvalds 	int k, devs_per_host;
52741da177e4SLinus Torvalds 	int error = 0;
52751da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
52768b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
52771da177e4SLinus Torvalds 
527824669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
52799a051019SDouglas Gilbert 	if (sdbg_host == NULL) {
5280c1287970STomas Winkler 		pr_err("out of memory at line %d\n", __LINE__);
52811da177e4SLinus Torvalds 		return -ENOMEM;
52821da177e4SLinus Torvalds 	}
52831da177e4SLinus Torvalds 
52841da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
52851da177e4SLinus Torvalds 
5286773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
52871da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
52885cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
52895cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
5290c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
52911da177e4SLinus Torvalds 			error = -ENOMEM;
52921da177e4SLinus Torvalds 			goto clean;
52931da177e4SLinus Torvalds 		}
52941da177e4SLinus Torvalds 	}
52951da177e4SLinus Torvalds 
52961da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
52971da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
52981da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
52991da177e4SLinus Torvalds 
53001da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
53019b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
53021da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
5303773642d9SDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
53041da177e4SLinus Torvalds 
53051da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
53061da177e4SLinus Torvalds 
53071da177e4SLinus Torvalds 	if (error)
53081da177e4SLinus Torvalds 		goto clean;
53091da177e4SLinus Torvalds 
5310773642d9SDouglas Gilbert 	++sdebug_add_host;
53111da177e4SLinus Torvalds 	return error;
53121da177e4SLinus Torvalds 
53131da177e4SLinus Torvalds clean:
53148b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
53158b40228fSFUJITA Tomonori 				 dev_list) {
53161da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
53171da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
53181da177e4SLinus Torvalds 	}
53191da177e4SLinus Torvalds 
53201da177e4SLinus Torvalds 	kfree(sdbg_host);
53211da177e4SLinus Torvalds 	return error;
53221da177e4SLinus Torvalds }
53231da177e4SLinus Torvalds 
53241da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
53251da177e4SLinus Torvalds {
53261da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
53271da177e4SLinus Torvalds 
53281da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
53291da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
53301da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
53311da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
53321da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
53331da177e4SLinus Torvalds 	}
53341da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
53351da177e4SLinus Torvalds 
53361da177e4SLinus Torvalds 	if (!sdbg_host)
53371da177e4SLinus Torvalds 		return;
53381da177e4SLinus Torvalds 
53391da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
5340773642d9SDouglas Gilbert 	--sdebug_add_host;
53411da177e4SLinus Torvalds }
53421da177e4SLinus Torvalds 
5343fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
5344cbf67842SDouglas Gilbert {
5345cbf67842SDouglas Gilbert 	int num_in_q = 0;
5346cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5347cbf67842SDouglas Gilbert 
5348c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
5349cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
5350cbf67842SDouglas Gilbert 	if (NULL == devip) {
5351c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
5352cbf67842SDouglas Gilbert 		return	-ENODEV;
5353cbf67842SDouglas Gilbert 	}
5354cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5355c40ecc12SChristoph Hellwig 
5356cbf67842SDouglas Gilbert 	if (qdepth < 1)
5357cbf67842SDouglas Gilbert 		qdepth = 1;
5358c4837394SDouglas Gilbert 	/* allow to exceed max host qc_arr elements for testing */
5359c4837394SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE + 10)
5360c4837394SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE + 10;
5361db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
5362cbf67842SDouglas Gilbert 
5363773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
5364c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
5365c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
5366cbf67842SDouglas Gilbert 	}
5367c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
5368cbf67842SDouglas Gilbert 	return sdev->queue_depth;
5369cbf67842SDouglas Gilbert }
5370cbf67842SDouglas Gilbert 
5371c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
5372817fd66bSDouglas Gilbert {
5373c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
5374773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
5375773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
5376773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
5377c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
5378773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
5379817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
5380c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
5381817fd66bSDouglas Gilbert 	}
5382c4837394SDouglas Gilbert 	return false;
5383817fd66bSDouglas Gilbert }
5384817fd66bSDouglas Gilbert 
53857ee6d1b4SBart Van Assche static bool fake_host_busy(struct scsi_cmnd *scp)
53867ee6d1b4SBart Van Assche {
53877ee6d1b4SBart Van Assche 	return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
53887ee6d1b4SBart Van Assche 		(atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
53897ee6d1b4SBart Van Assche }
53907ee6d1b4SBart Van Assche 
5391fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5392fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
5393c2248fc9SDouglas Gilbert {
5394c2248fc9SDouglas Gilbert 	u8 sdeb_i;
5395c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
5396c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
5397c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
5398c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
5399c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
5400c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5401c2248fc9SDouglas Gilbert 	int k, na;
5402c2248fc9SDouglas Gilbert 	int errsts = 0;
5403c2248fc9SDouglas Gilbert 	u32 flags;
5404c2248fc9SDouglas Gilbert 	u16 sa;
5405c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
5406c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
5407c2248fc9SDouglas Gilbert 
5408c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
5409c4837394SDouglas Gilbert 	if (sdebug_statistics)
5410c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
5411f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
5412f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
5413c2248fc9SDouglas Gilbert 		char b[120];
5414c2248fc9SDouglas Gilbert 		int n, len, sb;
5415c2248fc9SDouglas Gilbert 
5416c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
5417c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
5418c2248fc9SDouglas Gilbert 		if (len > 32)
5419c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
5420c2248fc9SDouglas Gilbert 		else {
5421c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
5422c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
5423c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
5424c2248fc9SDouglas Gilbert 		}
5425c4837394SDouglas Gilbert 		if (sdebug_mq_active)
5426c4837394SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n",
5427c4837394SDouglas Gilbert 				    my_name, blk_mq_unique_tag(scp->request),
5428c4837394SDouglas Gilbert 				    b);
5429c4837394SDouglas Gilbert 		else
5430c4837394SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name,
5431c4837394SDouglas Gilbert 				    b);
5432c2248fc9SDouglas Gilbert 	}
54337ee6d1b4SBart Van Assche 	if (fake_host_busy(scp))
54347ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
543534d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
5436f46eb0e9SDouglas Gilbert 	if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5437f46eb0e9SDouglas Gilbert 		goto err_out;
5438c2248fc9SDouglas Gilbert 
5439c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
5440c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
5441c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
5442f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
5443f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5444c2248fc9SDouglas Gilbert 		if (NULL == devip)
5445f46eb0e9SDouglas Gilbert 			goto err_out;
5446c2248fc9SDouglas Gilbert 	}
5447c2248fc9SDouglas Gilbert 	na = oip->num_attached;
5448c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
5449c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
5450c2248fc9SDouglas Gilbert 		r_oip = oip;
5451c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
5452c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
5453c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
5454c2248fc9SDouglas Gilbert 			else
5455c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
5456c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5457c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
5458c2248fc9SDouglas Gilbert 					break;
5459c2248fc9SDouglas Gilbert 			}
5460c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
5461c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5462c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
5463c2248fc9SDouglas Gilbert 					break;
5464c2248fc9SDouglas Gilbert 			}
5465c2248fc9SDouglas Gilbert 		}
5466c2248fc9SDouglas Gilbert 		if (k > na) {
5467c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
5468c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5469c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
5470c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5471c2248fc9SDouglas Gilbert 			else
5472c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
5473c2248fc9SDouglas Gilbert 			goto check_cond;
5474c2248fc9SDouglas Gilbert 		}
5475c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
5476c2248fc9SDouglas Gilbert 	flags = oip->flags;
5477f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
5478c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5479c2248fc9SDouglas Gilbert 		goto check_cond;
5480c2248fc9SDouglas Gilbert 	}
5481f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
5482773642d9SDouglas Gilbert 		if (sdebug_verbose)
5483773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5484773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
5485c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5486c2248fc9SDouglas Gilbert 		goto check_cond;
5487c2248fc9SDouglas Gilbert 	}
5488f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
5489c2248fc9SDouglas Gilbert 		u8 rem;
5490c2248fc9SDouglas Gilbert 		int j;
5491c2248fc9SDouglas Gilbert 
5492c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5493c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
5494c2248fc9SDouglas Gilbert 			if (rem) {
5495c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
5496c2248fc9SDouglas Gilbert 					if (0x80 & rem)
5497c2248fc9SDouglas Gilbert 						break;
5498c2248fc9SDouglas Gilbert 				}
5499c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5500c2248fc9SDouglas Gilbert 				goto check_cond;
5501c2248fc9SDouglas Gilbert 			}
5502c2248fc9SDouglas Gilbert 		}
5503c2248fc9SDouglas Gilbert 	}
5504f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
5505b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
5506b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
5507f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
5508c2248fc9SDouglas Gilbert 		if (errsts)
5509c2248fc9SDouglas Gilbert 			goto check_cond;
5510c2248fc9SDouglas Gilbert 	}
5511c4837394SDouglas Gilbert 	if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
5512c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
5513773642d9SDouglas Gilbert 		if (sdebug_verbose)
5514c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5515c2248fc9SDouglas Gilbert 				    "%s\n", my_name, "initializing command "
5516c2248fc9SDouglas Gilbert 				    "required");
5517c2248fc9SDouglas Gilbert 		errsts = check_condition_result;
5518c2248fc9SDouglas Gilbert 		goto fini;
5519c2248fc9SDouglas Gilbert 	}
5520773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
5521c2248fc9SDouglas Gilbert 		goto fini;
5522f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
5523c4837394SDouglas Gilbert 		if (fake_timeout(scp))
5524c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
5525c2248fc9SDouglas Gilbert 	}
5526f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
5527f46eb0e9SDouglas Gilbert 		errsts = oip->pfp(scp, devip);	/* calls a resp_* function */
5528c2248fc9SDouglas Gilbert 	else if (r_pfp)	/* if leaf function ptr NULL, try the root's */
5529c2248fc9SDouglas Gilbert 		errsts = r_pfp(scp, devip);
5530c2248fc9SDouglas Gilbert 
5531c2248fc9SDouglas Gilbert fini:
5532c2248fc9SDouglas Gilbert 	return schedule_resp(scp, devip, errsts,
5533c2206098SDouglas Gilbert 			     ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay));
5534c2248fc9SDouglas Gilbert check_cond:
5535c2248fc9SDouglas Gilbert 	return schedule_resp(scp, devip, check_condition_result, 0);
5536f46eb0e9SDouglas Gilbert err_out:
5537f46eb0e9SDouglas Gilbert 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0);
5538c2248fc9SDouglas Gilbert }
5539c2248fc9SDouglas Gilbert 
55409e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
5541c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
5542c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
55439e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
55449e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
55459e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
55469e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
55479e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
55489e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
55499e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
5550185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
5551cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
55529e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
55539e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
5554cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
5555cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
55569e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
5557c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
55589e603ca0SFUJITA Tomonori 	.this_id =		7,
555965e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
5560cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
55616bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
55629e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
55639e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
5564c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
55659e603ca0SFUJITA Tomonori };
55669e603ca0SFUJITA Tomonori 
55671da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev)
55681da177e4SLinus Torvalds {
55691da177e4SLinus Torvalds 	int error = 0;
55701da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
55711da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
5572f46eb0e9SDouglas Gilbert 	int hprot;
55731da177e4SLinus Torvalds 
55741da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
55751da177e4SLinus Torvalds 
5576773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
5577773642d9SDouglas Gilbert 	if (sdebug_clustering)
55780759c666SAkinobu Mita 		sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
55791da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
55801da177e4SLinus Torvalds 	if (NULL == hpnt) {
5581c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
55821da177e4SLinus Torvalds 		error = -ENODEV;
55831da177e4SLinus Torvalds 		return error;
55841da177e4SLinus Torvalds 	}
5585c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
55869b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
5587c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
5588c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
5589c4837394SDouglas Gilbert 	}
5590c4837394SDouglas Gilbert 	/* Decide whether to tell scsi subsystem that we want mq */
5591c4837394SDouglas Gilbert 	/* Following should give the same answer for each host */
5592c4837394SDouglas Gilbert 	sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1);
5593c4837394SDouglas Gilbert 	if (sdebug_mq_active)
5594c4837394SDouglas Gilbert 		hpnt->nr_hw_queues = submit_queues;
55951da177e4SLinus Torvalds 
55961da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
55971da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
5598773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5599773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
56001da177e4SLinus Torvalds 	else
5601773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
5602773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
5603f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
56041da177e4SLinus Torvalds 
5605f46eb0e9SDouglas Gilbert 	hprot = 0;
5606c6a44287SMartin K. Petersen 
5607773642d9SDouglas Gilbert 	switch (sdebug_dif) {
5608c6a44287SMartin K. Petersen 
56098475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
5610f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
5611773642d9SDouglas Gilbert 		if (sdebug_dix)
5612f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
5613c6a44287SMartin K. Petersen 		break;
5614c6a44287SMartin K. Petersen 
56158475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
5616f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
5617773642d9SDouglas Gilbert 		if (sdebug_dix)
5618f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
5619c6a44287SMartin K. Petersen 		break;
5620c6a44287SMartin K. Petersen 
56218475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
5622f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
5623773642d9SDouglas Gilbert 		if (sdebug_dix)
5624f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
5625c6a44287SMartin K. Petersen 		break;
5626c6a44287SMartin K. Petersen 
5627c6a44287SMartin K. Petersen 	default:
5628773642d9SDouglas Gilbert 		if (sdebug_dix)
5629f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
5630c6a44287SMartin K. Petersen 		break;
5631c6a44287SMartin K. Petersen 	}
5632c6a44287SMartin K. Petersen 
5633f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
5634c6a44287SMartin K. Petersen 
5635f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
5636c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
5637f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5638f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5639f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5640f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5641f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5642f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5643f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
5644c6a44287SMartin K. Petersen 
5645773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
5646c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5647c6a44287SMartin K. Petersen 	else
5648c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5649c6a44287SMartin K. Petersen 
5650773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5651773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
5652c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
5653c4837394SDouglas Gilbert 		sdebug_statistics = true;
56541da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
56551da177e4SLinus Torvalds 	if (error) {
5656c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
56571da177e4SLinus Torvalds 		error = -ENODEV;
56581da177e4SLinus Torvalds 		scsi_host_put(hpnt);
56591da177e4SLinus Torvalds 	} else
56601da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
56611da177e4SLinus Torvalds 
56621da177e4SLinus Torvalds 	return error;
56631da177e4SLinus Torvalds }
56641da177e4SLinus Torvalds 
56651da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev)
56661da177e4SLinus Torvalds {
56671da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
56688b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
56691da177e4SLinus Torvalds 
56701da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
56711da177e4SLinus Torvalds 
56721da177e4SLinus Torvalds 	if (!sdbg_host) {
5673c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
56741da177e4SLinus Torvalds 		return -ENODEV;
56751da177e4SLinus Torvalds 	}
56761da177e4SLinus Torvalds 
56771da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
56781da177e4SLinus Torvalds 
56798b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
56808b40228fSFUJITA Tomonori 				 dev_list) {
56811da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
56821da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
56831da177e4SLinus Torvalds 	}
56841da177e4SLinus Torvalds 
56851da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
56861da177e4SLinus Torvalds 	return 0;
56871da177e4SLinus Torvalds }
56881da177e4SLinus Torvalds 
56898dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
56908dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
56911da177e4SLinus Torvalds {
56928dea0d02SFUJITA Tomonori 	return 1;
56938dea0d02SFUJITA Tomonori }
56941da177e4SLinus Torvalds 
56958dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
56968dea0d02SFUJITA Tomonori 	.name = "pseudo",
56978dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
56988dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
56998dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
570082069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
57018dea0d02SFUJITA Tomonori };
5702