xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 7ee6d1b4)
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)
238fd32119bSDouglas Gilbert #define FF_DIRECT_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 */
311fd32119bSDouglas Gilbert 	u8 len_mask[16];	/* len=len_mask[0], then mask for cdb[1]... */
312fd32119bSDouglas Gilbert 				/* ignore cdb bytes after position 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,
329c2248fc9SDouglas Gilbert 	SDEB_I_SERV_ACT_IN = 12,	/* 12, 16 */
330c2248fc9SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT = 13,	/* 12, 16 */
331c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
332c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
333c2248fc9SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* 10 only */
334c2248fc9SDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,
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,
347c2248fc9SDouglas Gilbert 	SDEB_I_LAST_ELEMENT = 30,	/* keep this last */
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,
379c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT,
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,
383c2248fc9SDouglas Gilbert 	SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN,
384c2248fc9SDouglas Gilbert 	     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 
416c2248fc9SDouglas Gilbert static const struct opcode_info_t msense_iarr[1] = {
417c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
418c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
419c2248fc9SDouglas Gilbert };
420c2248fc9SDouglas Gilbert 
421c2248fc9SDouglas Gilbert static const struct opcode_info_t mselect_iarr[1] = {
422c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
423c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
424c2248fc9SDouglas Gilbert };
425c2248fc9SDouglas Gilbert 
426c2248fc9SDouglas Gilbert static const struct opcode_info_t read_iarr[3] = {
427c2248fc9SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */
428c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
429c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
430c2248fc9SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */
431c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
432c2248fc9SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */
433c2248fc9SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
434c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
435c2248fc9SDouglas Gilbert };
436c2248fc9SDouglas Gilbert 
437c2248fc9SDouglas Gilbert static const struct opcode_info_t write_iarr[3] = {
438c2248fc9SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,   /* 10 */
439c2248fc9SDouglas Gilbert 	    {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
440c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
441c2248fc9SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,    /* 6 */
442c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
443c2248fc9SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,   /* 12 */
444c2248fc9SDouglas Gilbert 	    {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
445c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
446c2248fc9SDouglas Gilbert };
447c2248fc9SDouglas Gilbert 
448c2248fc9SDouglas Gilbert static const struct opcode_info_t sa_in_iarr[1] = {
449c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
450c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
451c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },
452c2248fc9SDouglas Gilbert };
453c2248fc9SDouglas Gilbert 
454c2248fc9SDouglas Gilbert static const struct opcode_info_t vl_iarr[1] = {	/* VARIABLE LENGTH */
455c2248fc9SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0,
456c2248fc9SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa,
457c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
458c2248fc9SDouglas Gilbert };
459c2248fc9SDouglas Gilbert 
460c2248fc9SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[2] = {
46138d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
462c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
463c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
46438d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
465c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
466c2248fc9SDouglas Gilbert 	     0, 0} },
467c2248fc9SDouglas Gilbert };
468c2248fc9SDouglas Gilbert 
469c2248fc9SDouglas Gilbert static const struct opcode_info_t write_same_iarr[1] = {
470c2248fc9SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL,
471c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
472c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x1f, 0xc7} },
473c2248fc9SDouglas Gilbert };
474c2248fc9SDouglas Gilbert 
475c2248fc9SDouglas Gilbert static const struct opcode_info_t reserve_iarr[1] = {
476c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,	/* RESERVE(6) */
477c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
478c2248fc9SDouglas Gilbert };
479c2248fc9SDouglas Gilbert 
480c2248fc9SDouglas Gilbert static const struct opcode_info_t release_iarr[1] = {
481c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,	/* RELEASE(6) */
482c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
483c2248fc9SDouglas Gilbert };
484c2248fc9SDouglas Gilbert 
485c2248fc9SDouglas Gilbert 
486c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
487c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
488c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
489c2248fc9SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
490c2248fc9SDouglas Gilbert /* 0 */
491c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,
492c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
493c2248fc9SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL,
494c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
495c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
496c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
497c2248fc9SDouglas Gilbert 	     0, 0} },
498c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
499c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
500c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
501c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
502c2248fc9SDouglas Gilbert 	{1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr,
503c2248fc9SDouglas Gilbert 	    {10,  0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
504c2248fc9SDouglas Gilbert 	     0} },
505c2248fc9SDouglas Gilbert 	{1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr,
506c2248fc9SDouglas Gilbert 	    {10,  0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
507c2248fc9SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,
508c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
509c2248fc9SDouglas Gilbert 	     0, 0, 0} },
510c2248fc9SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,
511c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
512c2248fc9SDouglas Gilbert 	     0, 0} },
513c2248fc9SDouglas Gilbert 	{3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr,
514c2248fc9SDouglas Gilbert 	    {16,  0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
515c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x9f, 0xc7} },		/* READ(16) */
516c2248fc9SDouglas Gilbert /* 10 */
517c2248fc9SDouglas Gilbert 	{3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr,
518c2248fc9SDouglas Gilbert 	    {16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
519c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x9f, 0xc7} },		/* WRITE(16) */
520c2248fc9SDouglas Gilbert 	{0, 0x1b, 0, 0, resp_start_stop, NULL,		/* START STOP UNIT */
521c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
522c2248fc9SDouglas Gilbert 	{1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr,
523c2248fc9SDouglas Gilbert 	    {16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
524c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x1, 0xc7} },	/* READ CAPACITY(16) */
525c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */
526c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
527c2248fc9SDouglas Gilbert 	{2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr,
528c2248fc9SDouglas Gilbert 	    {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0,
529c2248fc9SDouglas Gilbert 	     0} },
530c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
531c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
532f7f9f26bSDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */
533f7f9f26bSDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
534f7f9f26bSDouglas Gilbert 	     0, 0, 0, 0, 0, 0} },
535c2248fc9SDouglas Gilbert 	{1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0,
536c2248fc9SDouglas Gilbert 	    vl_iarr, {32,  0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0,
537c2248fc9SDouglas Gilbert 		      0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */
538c2248fc9SDouglas Gilbert 	{1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */
539c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
540c2248fc9SDouglas Gilbert 	     0} },
541c2248fc9SDouglas Gilbert 	{1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */
542c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
543c2248fc9SDouglas Gilbert 	     0} },
544c2248fc9SDouglas Gilbert /* 20 */
545f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
546f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
547c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
548c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
549c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
550c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
551c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
552c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
553c2248fc9SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */
554c2248fc9SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
555c2248fc9SDouglas Gilbert 	{0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10,
556c2248fc9SDouglas Gilbert 	    NULL, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7,
557c2248fc9SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
558acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
559acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
560acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
561c2248fc9SDouglas Gilbert 	{1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10,
562c2248fc9SDouglas Gilbert 	    write_same_iarr, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff,
563c2248fc9SDouglas Gilbert 			      0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
564c2248fc9SDouglas Gilbert 	{0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */
565c2248fc9SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
566c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
56738d5c833SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL,
568c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
569c2248fc9SDouglas Gilbert 	     0, 0xff, 0x1f, 0xc7} },		/* COMPARE AND WRITE */
570c2248fc9SDouglas Gilbert 
571c2248fc9SDouglas Gilbert /* 30 */
572c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
573c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
574c2248fc9SDouglas Gilbert };
575c2248fc9SDouglas Gilbert 
576773642d9SDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;
577773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
5789b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
579c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
580773642d9SDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
581773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
582773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
583773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
584773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
585773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
586773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
587773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
588773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
589c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
590cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
591c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
592773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
593773642d9SDouglas Gilbert static int sdebug_no_uld;
594773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
595773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
596773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
597773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
598773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
59986e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
600b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
601773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
602773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
603773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
604773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
605773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
606773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
607773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
608773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
609773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
610773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
611773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
612773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
613773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
61409ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
615773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
616773642d9SDouglas Gilbert static bool sdebug_clustering;
617773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
618773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
619817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
620773642d9SDouglas Gilbert static bool sdebug_verbose;
621f46eb0e9SDouglas Gilbert static bool have_dif_prot;
622c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
623c4837394SDouglas Gilbert static bool sdebug_mq_active;
6241da177e4SLinus Torvalds 
625c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
6261da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
6271da177e4SLinus Torvalds 
6281da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
6291da177e4SLinus Torvalds    may still need them */
6301da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
6311da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
6321da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
6331da177e4SLinus Torvalds 
6341da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
6351da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
6361da177e4SLinus Torvalds 
6371da177e4SLinus Torvalds static unsigned char *fake_storep;	/* ramdisk storage */
6386ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_storep;	/* protection info */
63944d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
6401da177e4SLinus Torvalds 
64144d92694SMartin K. Petersen static unsigned long map_size;
642cbf67842SDouglas Gilbert static int num_aborts;
643cbf67842SDouglas Gilbert static int num_dev_resets;
644cbf67842SDouglas Gilbert static int num_target_resets;
645cbf67842SDouglas Gilbert static int num_bus_resets;
646cbf67842SDouglas Gilbert static int num_host_resets;
647c6a44287SMartin K. Petersen static int dix_writes;
648c6a44287SMartin K. Petersen static int dix_reads;
649c6a44287SMartin K. Petersen static int dif_errors;
6501da177e4SLinus Torvalds 
651c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
652c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
653fd32119bSDouglas Gilbert 
6541da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
6551da177e4SLinus Torvalds 
656cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
657cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
6581da177e4SLinus Torvalds 
6591da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
6601da177e4SLinus Torvalds 
6611da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
6621da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
6631da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
6641da177e4SLinus Torvalds };
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds static const int check_condition_result =
6671da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
6681da177e4SLinus Torvalds 
669c6a44287SMartin K. Petersen static const int illegal_condition_result =
670c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
671c6a44287SMartin K. Petersen 
672cbf67842SDouglas Gilbert static const int device_qfull_result =
673cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
674cbf67842SDouglas Gilbert 
675fd32119bSDouglas Gilbert 
676760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
677760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
678760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
679760f3b03SDouglas Gilbert  */
680760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
681fd32119bSDouglas Gilbert {
682fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
683fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
684fd32119bSDouglas Gilbert }
685c65b1445SDouglas Gilbert 
68614faa944SAkinobu Mita static void *fake_store(unsigned long long lba)
68714faa944SAkinobu Mita {
68814faa944SAkinobu Mita 	lba = do_div(lba, sdebug_store_sectors);
68914faa944SAkinobu Mita 
690773642d9SDouglas Gilbert 	return fake_storep + lba * sdebug_sector_size;
69114faa944SAkinobu Mita }
69214faa944SAkinobu Mita 
6936ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_store(sector_t sector)
69414faa944SAkinobu Mita {
69549413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
69614faa944SAkinobu Mita 
69714faa944SAkinobu Mita 	return dif_storep + sector;
69814faa944SAkinobu Mita }
69914faa944SAkinobu Mita 
7008dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
7018dea0d02SFUJITA Tomonori {
7028dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
7038dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
7048dea0d02SFUJITA Tomonori 
7058dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
7068dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
7078dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
7088dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
709773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
710773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
7118dea0d02SFUJITA Tomonori 		else
712773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
713773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
714f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
7158dea0d02SFUJITA Tomonori 	}
7168dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
7178dea0d02SFUJITA Tomonori }
7188dea0d02SFUJITA Tomonori 
71922017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
72022017ed2SDouglas Gilbert 
72122017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
722fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
723fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
72422017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
72522017ed2SDouglas Gilbert {
72622017ed2SDouglas Gilbert 	unsigned char *sbuff;
72722017ed2SDouglas Gilbert 	u8 sks[4];
72822017ed2SDouglas Gilbert 	int sl, asc;
72922017ed2SDouglas Gilbert 
73022017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
73122017ed2SDouglas Gilbert 	if (!sbuff) {
73222017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
73322017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
73422017ed2SDouglas Gilbert 		return;
73522017ed2SDouglas Gilbert 	}
73622017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
73722017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
738773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
73922017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
74022017ed2SDouglas Gilbert 	sks[0] = 0x80;
74122017ed2SDouglas Gilbert 	if (c_d)
74222017ed2SDouglas Gilbert 		sks[0] |= 0x40;
74322017ed2SDouglas Gilbert 	if (in_bit >= 0) {
74422017ed2SDouglas Gilbert 		sks[0] |= 0x8;
74522017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
74622017ed2SDouglas Gilbert 	}
74722017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
748773642d9SDouglas Gilbert 	if (sdebug_dsense) {
74922017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
75022017ed2SDouglas Gilbert 		sbuff[7] = sl;
75122017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
75222017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
75322017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
75422017ed2SDouglas Gilbert 	} else
75522017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
756773642d9SDouglas Gilbert 	if (sdebug_verbose)
75722017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
75822017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
75922017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
76022017ed2SDouglas Gilbert }
76122017ed2SDouglas Gilbert 
762cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
7638dea0d02SFUJITA Tomonori {
7648dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
7658dea0d02SFUJITA Tomonori 
766cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
767cbf67842SDouglas Gilbert 	if (!sbuff) {
768cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
769cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
770cbf67842SDouglas Gilbert 		return;
771cbf67842SDouglas Gilbert 	}
772cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
7738dea0d02SFUJITA Tomonori 
774773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
7758dea0d02SFUJITA Tomonori 
776773642d9SDouglas Gilbert 	if (sdebug_verbose)
777cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
778cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
779cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
7808dea0d02SFUJITA Tomonori }
7811da177e4SLinus Torvalds 
782fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
78322017ed2SDouglas Gilbert {
78422017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
78522017ed2SDouglas Gilbert }
78622017ed2SDouglas Gilbert 
7871da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
7881da177e4SLinus Torvalds {
789773642d9SDouglas Gilbert 	if (sdebug_verbose) {
790cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
791cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
792cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
793cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
794cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
795cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
796cbf67842SDouglas Gilbert 				    __func__);
797cbf67842SDouglas Gilbert 		else
798cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
799cbf67842SDouglas Gilbert 				    __func__, cmd);
8001da177e4SLinus Torvalds 	}
8011da177e4SLinus Torvalds 	return -EINVAL;
8021da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
8031da177e4SLinus Torvalds }
8041da177e4SLinus Torvalds 
8059b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
8069b760fd8SDouglas Gilbert {
8079b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
8089b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
8099b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8109b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8119b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8129b760fd8SDouglas Gilbert 		break;
8139b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
8149b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8159b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8169b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8179b760fd8SDouglas Gilbert 		break;
8189b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
8199b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8209b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8219b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8229b760fd8SDouglas Gilbert 		break;
8239b760fd8SDouglas Gilbert 	case 16:
8249b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8259b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
8269b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8279b760fd8SDouglas Gilbert 		break;
8289b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
8299b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8309b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
8319b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8329b760fd8SDouglas Gilbert 		break;
8339b760fd8SDouglas Gilbert 	default:
8349b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
8359b760fd8SDouglas Gilbert 			sdebug_cdb_len);
8369b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8379b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8389b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8399b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
8409b760fd8SDouglas Gilbert 		break;
8419b760fd8SDouglas Gilbert 	}
8429b760fd8SDouglas Gilbert }
8439b760fd8SDouglas Gilbert 
8449b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
8459b760fd8SDouglas Gilbert {
8469b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
8479b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
8489b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
8499b760fd8SDouglas Gilbert 
8509b760fd8SDouglas Gilbert 	spin_lock(&sdebug_host_list_lock);
8519b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
8529b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
8539b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
8549b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
8559b760fd8SDouglas Gilbert 		}
8569b760fd8SDouglas Gilbert 	}
8579b760fd8SDouglas Gilbert 	spin_unlock(&sdebug_host_list_lock);
8589b760fd8SDouglas Gilbert }
8599b760fd8SDouglas Gilbert 
86019c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
86119c8ead7SEwan D. Milne {
86219c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
86319c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
86419c8ead7SEwan D. Milne 
86519c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
86619c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
86719c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
86819c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
86919c8ead7SEwan D. Milne 			    (devip->target == dp->target))
87019c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
87119c8ead7SEwan D. Milne 		}
87219c8ead7SEwan D. Milne 	}
87319c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
87419c8ead7SEwan D. Milne }
87519c8ead7SEwan D. Milne 
876f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
8771da177e4SLinus Torvalds {
878cbf67842SDouglas Gilbert 	int k;
879cbf67842SDouglas Gilbert 
880cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
881cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
882cbf67842SDouglas Gilbert 		const char *cp = NULL;
883cbf67842SDouglas Gilbert 
884cbf67842SDouglas Gilbert 		switch (k) {
885cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
886f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
887f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
888773642d9SDouglas Gilbert 			if (sdebug_verbose)
889cbf67842SDouglas Gilbert 				cp = "power on reset";
890cbf67842SDouglas Gilbert 			break;
891cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
892f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
893f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
894773642d9SDouglas Gilbert 			if (sdebug_verbose)
895cbf67842SDouglas Gilbert 				cp = "bus reset";
896cbf67842SDouglas Gilbert 			break;
897cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
898f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
899f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
900773642d9SDouglas Gilbert 			if (sdebug_verbose)
901cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
902cbf67842SDouglas Gilbert 			break;
9030d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
904f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
905f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
906773642d9SDouglas Gilbert 			if (sdebug_verbose)
9070d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
908f49accf1SEwan D. Milne 			break;
909acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
910f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
911b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
912b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
913773642d9SDouglas Gilbert 			if (sdebug_verbose)
914acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
915acafd0b9SEwan D. Milne 			break;
916acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
917f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
918acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
919acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
920773642d9SDouglas Gilbert 			if (sdebug_verbose)
921acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
922acafd0b9SEwan D. Milne 			break;
92319c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
92419c8ead7SEwan D. Milne 			/*
92519c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
92619c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
92719c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
92819c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
929773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
93019c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
93119c8ead7SEwan D. Milne 			 */
932773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
93319c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
934f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
93519c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
93619c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
937773642d9SDouglas Gilbert 			if (sdebug_verbose)
93819c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
93919c8ead7SEwan D. Milne 			break;
940cbf67842SDouglas Gilbert 		default:
941773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
942773642d9SDouglas Gilbert 			if (sdebug_verbose)
943cbf67842SDouglas Gilbert 				cp = "unknown";
944cbf67842SDouglas Gilbert 			break;
945cbf67842SDouglas Gilbert 		}
946cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
947773642d9SDouglas Gilbert 		if (sdebug_verbose)
948f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
949cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
950cbf67842SDouglas Gilbert 				   my_name, cp);
9511da177e4SLinus Torvalds 		return check_condition_result;
9521da177e4SLinus Torvalds 	}
9531da177e4SLinus Torvalds 	return 0;
9541da177e4SLinus Torvalds }
9551da177e4SLinus Torvalds 
956fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
9571da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
9581da177e4SLinus Torvalds 				int arr_len)
9591da177e4SLinus Torvalds {
96021a61829SFUJITA Tomonori 	int act_len;
961072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
9621da177e4SLinus Torvalds 
963072d0bb3SFUJITA Tomonori 	if (!sdb->length)
9641da177e4SLinus Torvalds 		return 0;
965072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
966773642d9SDouglas Gilbert 		return DID_ERROR << 16;
96721a61829SFUJITA Tomonori 
96821a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
96921a61829SFUJITA Tomonori 				      arr, arr_len);
97021a61829SFUJITA Tomonori 	sdb->resid = scsi_bufflen(scp) - act_len;
97121a61829SFUJITA Tomonori 
9721da177e4SLinus Torvalds 	return 0;
9731da177e4SLinus Torvalds }
9741da177e4SLinus Torvalds 
975fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
976fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
977fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
978fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
979fb0cc8d1SDouglas Gilbert  */
980fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
981fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
982fb0cc8d1SDouglas Gilbert {
983fb0cc8d1SDouglas Gilbert 	int act_len, n;
984fb0cc8d1SDouglas Gilbert 	struct scsi_data_buffer *sdb = scsi_in(scp);
985fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
986fb0cc8d1SDouglas Gilbert 
987fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
988fb0cc8d1SDouglas Gilbert 		return 0;
989fb0cc8d1SDouglas Gilbert 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
990fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
991fb0cc8d1SDouglas Gilbert 
992fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
993fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
994fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
995fb0cc8d1SDouglas Gilbert 		 __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid);
996fb0cc8d1SDouglas Gilbert 	n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
997fb0cc8d1SDouglas Gilbert 	sdb->resid = min(sdb->resid, n);
998fb0cc8d1SDouglas Gilbert 	return 0;
999fb0cc8d1SDouglas Gilbert }
1000fb0cc8d1SDouglas Gilbert 
1001fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1002fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1003fb0cc8d1SDouglas Gilbert  */
10041da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
100521a61829SFUJITA Tomonori 			       int arr_len)
10061da177e4SLinus Torvalds {
100721a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
10081da177e4SLinus Torvalds 		return 0;
1009072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
10101da177e4SLinus Torvalds 		return -1;
101121a61829SFUJITA Tomonori 
101221a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
10131da177e4SLinus Torvalds }
10141da177e4SLinus Torvalds 
10151da177e4SLinus Torvalds 
1016e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1017e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
10189b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
10191b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
10201b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
10211b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
10221b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
10231da177e4SLinus Torvalds 
1024cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
1025760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
10265a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
102709ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1028bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
10291da177e4SLinus Torvalds {
1030c65b1445SDouglas Gilbert 	int num, port_a;
1031c65b1445SDouglas Gilbert 	char b[32];
10321da177e4SLinus Torvalds 
1033c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
10341da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
10351da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
10361da177e4SLinus Torvalds 	arr[1] = 0x1;
10371da177e4SLinus Torvalds 	arr[2] = 0x0;
1038e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1039e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
10401da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
10411da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
10421da177e4SLinus Torvalds 	arr[3] = num;
10431da177e4SLinus Torvalds 	num += 4;
1044c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
104509ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
104609ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
104709ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
104809ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
104909ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
105009ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
105109ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
105209ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
105309ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
105409ba24c1SDouglas Gilbert 			num += 16;
105509ba24c1SDouglas Gilbert 		} else {
10561b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1057c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1058c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1059c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1060c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
10611b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1062773642d9SDouglas Gilbert 			num += 8;
106309ba24c1SDouglas Gilbert 		}
1064c65b1445SDouglas Gilbert 		/* Target relative port number */
1065c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1066c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1067c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1068c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1069c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1070c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1071c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1072c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1073c65b1445SDouglas Gilbert 	}
10741b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1075c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1076c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1077c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1078c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
10791b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1080773642d9SDouglas Gilbert 	num += 8;
10811b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
10825a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
10835a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
10845a09e398SHannes Reinecke 	arr[num++] = 0x0;
10855a09e398SHannes Reinecke 	arr[num++] = 0x4;
10865a09e398SHannes Reinecke 	arr[num++] = 0;
10875a09e398SHannes Reinecke 	arr[num++] = 0;
1088773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1089773642d9SDouglas Gilbert 	num += 2;
10901b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1091c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1092c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1093c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1094c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
10951b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1096773642d9SDouglas Gilbert 	num += 8;
1097c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1098c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1099c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1100c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1101c65b1445SDouglas Gilbert 	arr[num++] = 24;
11021b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1103c65b1445SDouglas Gilbert 	num += 12;
1104c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1105c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1106c65b1445SDouglas Gilbert 	num += 8;
1107c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1108c65b1445SDouglas Gilbert 	num += 4;
1109c65b1445SDouglas Gilbert 	return num;
1110c65b1445SDouglas Gilbert }
1111c65b1445SDouglas Gilbert 
1112c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1113c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1114c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1115c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1116c65b1445SDouglas Gilbert };
1117c65b1445SDouglas Gilbert 
1118cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1119760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1120c65b1445SDouglas Gilbert {
1121c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1122c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1123c65b1445SDouglas Gilbert }
1124c65b1445SDouglas Gilbert 
1125cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1126760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1127c65b1445SDouglas Gilbert {
1128c65b1445SDouglas Gilbert 	int num = 0;
1129c65b1445SDouglas Gilbert 	const char * na1 = "https://www.kernel.org/config";
1130c65b1445SDouglas Gilbert 	const char * na2 = "http://www.kernel.org/log";
1131c65b1445SDouglas Gilbert 	int plen, olen;
1132c65b1445SDouglas Gilbert 
1133c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1134c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1135c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1136c65b1445SDouglas Gilbert 	olen = strlen(na1);
1137c65b1445SDouglas Gilbert 	plen = olen + 1;
1138c65b1445SDouglas Gilbert 	if (plen % 4)
1139c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1140c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1141c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1142c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1143c65b1445SDouglas Gilbert 	num += plen;
1144c65b1445SDouglas Gilbert 
1145c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1146c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1147c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1148c65b1445SDouglas Gilbert 	olen = strlen(na2);
1149c65b1445SDouglas Gilbert 	plen = olen + 1;
1150c65b1445SDouglas Gilbert 	if (plen % 4)
1151c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1152c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1153c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1154c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1155c65b1445SDouglas Gilbert 	num += plen;
1156c65b1445SDouglas Gilbert 
1157c65b1445SDouglas Gilbert 	return num;
1158c65b1445SDouglas Gilbert }
1159c65b1445SDouglas Gilbert 
1160c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1161760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1162c65b1445SDouglas Gilbert {
1163c65b1445SDouglas Gilbert 	int num = 0;
1164c65b1445SDouglas Gilbert 	int port_a, port_b;
1165c65b1445SDouglas Gilbert 
1166c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1167c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1168c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1169c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1170c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1171c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1172c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1173c65b1445SDouglas Gilbert 	num += 6;
1174c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1175c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1176c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1177c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1178c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1179c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1180c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
11811b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1182773642d9SDouglas Gilbert 	num += 8;
1183c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1184c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1185c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1186c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1187c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1188c65b1445SDouglas Gilbert 	num += 6;
1189c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1190c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1191c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1192c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1193c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1194c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1195c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
11961b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1197773642d9SDouglas Gilbert 	num += 8;
1198c65b1445SDouglas Gilbert 
1199c65b1445SDouglas Gilbert 	return num;
1200c65b1445SDouglas Gilbert }
1201c65b1445SDouglas Gilbert 
1202c65b1445SDouglas Gilbert 
1203c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1204c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1205c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1206c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1207c65b1445SDouglas Gilbert '1','2','3','4',
1208c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1209c65b1445SDouglas Gilbert 0xec,0,0,0,
1210c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1211c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1212c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1213c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1214c65b1445SDouglas Gilbert 0x53,0x41,
1215c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1216c65b1445SDouglas Gilbert 0x20,0x20,
1217c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1218c65b1445SDouglas Gilbert 0x10,0x80,
1219c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1220c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1221c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1222c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1223c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1224c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1225c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1226c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1227c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1228c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1229c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1230c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1231c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1232c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1233c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1234c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1235c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1236c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1237c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1238c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1239c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1240c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1241c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1242c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,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,0xa5,0x51,
1245c65b1445SDouglas Gilbert };
1246c65b1445SDouglas Gilbert 
1247cbf67842SDouglas Gilbert /* ATA Information VPD page */
1248760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1249c65b1445SDouglas Gilbert {
1250c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1251c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1252c65b1445SDouglas Gilbert }
1253c65b1445SDouglas Gilbert 
1254c65b1445SDouglas Gilbert 
1255c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
12561e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
12571e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12581e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12591e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1260c65b1445SDouglas Gilbert };
1261c65b1445SDouglas Gilbert 
1262cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1263760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1264c65b1445SDouglas Gilbert {
1265ea61fca5SMartin K. Petersen 	unsigned int gran;
1266ea61fca5SMartin K. Petersen 
1267c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1268e308b3d1SMartin K. Petersen 
1269e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
127086e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
127186e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
127286e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
127386e6828aSLukas Herbolt 	else
1274773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1275773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1276e308b3d1SMartin K. Petersen 
1277e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1278773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1279773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
128044d92694SMartin K. Petersen 
1281e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1282773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1283e308b3d1SMartin K. Petersen 
1284773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1285e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1286773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1287e308b3d1SMartin K. Petersen 
1288e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1289773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
129044d92694SMartin K. Petersen 	}
129144d92694SMartin K. Petersen 
1292e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1293773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1294773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
129544d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
129644d92694SMartin K. Petersen 	}
129744d92694SMartin K. Petersen 
1298e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1299773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
13006014759cSMartin K. Petersen 
13015b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1302773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
13035b94e232SMartin K. Petersen 
13045b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
130544d92694SMartin K. Petersen 
1306c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
13071da177e4SLinus Torvalds }
13081da177e4SLinus Torvalds 
13091e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
1310760f3b03SDouglas Gilbert static int inquiry_vpd_b1(unsigned char *arr)
1311eac6e8e4SMatthew Wilcox {
1312eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1313eac6e8e4SMatthew Wilcox 	arr[0] = 0;
13141e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
13151e49f785SDouglas Gilbert 	arr[2] = 0;
13161e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
1317eac6e8e4SMatthew Wilcox 
1318eac6e8e4SMatthew Wilcox 	return 0x3c;
1319eac6e8e4SMatthew Wilcox }
13201da177e4SLinus Torvalds 
1321760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1322760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
13236014759cSMartin K. Petersen {
13243f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
13256014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1326773642d9SDouglas Gilbert 	if (sdebug_lbpu)
13276014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1328773642d9SDouglas Gilbert 	if (sdebug_lbpws)
13296014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1330773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
13315b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1332760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1333760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1334760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1335760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1336760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
13373f0bc3b3SMartin K. Petersen 	return 0x4;
13386014759cSMartin K. Petersen }
13396014759cSMartin K. Petersen 
13401da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1341c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
13421da177e4SLinus Torvalds 
1343c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
13441da177e4SLinus Torvalds {
13451da177e4SLinus Torvalds 	unsigned char pq_pdt;
13465a09e398SHannes Reinecke 	unsigned char * arr;
134701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
13485a09e398SHannes Reinecke 	int alloc_len, n, ret;
1349760f3b03SDouglas Gilbert 	bool have_wlun, is_disk;
13501da177e4SLinus Torvalds 
1351773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
13526f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
13536f3cbf55SDouglas Gilbert 	if (! arr)
13546f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1355760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
1356b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1357c2248fc9SDouglas Gilbert 	if (have_wlun)
1358b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1359b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1360b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1361c65b1445SDouglas Gilbert 	else
1362773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
13631da177e4SLinus Torvalds 	arr[0] = pq_pdt;
13641da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
136522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
13665a09e398SHannes Reinecke 		kfree(arr);
13671da177e4SLinus Torvalds 		return check_condition_result;
13681da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
13695a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1370c65b1445SDouglas Gilbert 		char lu_id_str[6];
1371c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
13721da177e4SLinus Torvalds 
13735a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
13745a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1375b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
137623183910SDouglas Gilbert 			host_no = 0;
1377c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1378c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1379c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1380c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1381c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
13821da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1383c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1384c65b1445SDouglas Gilbert 			n = 4;
1385c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1386c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1387c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1388c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1389c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1390c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1391c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1392c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1393760f3b03SDouglas Gilbert 			if (is_disk) {	  /* SBC only */
1394c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1395760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1396760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1397760f3b03SDouglas Gilbert 				arr[n++] = 0xb2;  /* Logical Block Prov */
1398760f3b03SDouglas Gilbert 			}
1399c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
14001da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1401c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
14021da177e4SLinus Torvalds 			arr[3] = len;
1403c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
14041da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1405c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1406760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
14075a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
140809ba24c1SDouglas Gilbert 						lu_id_str, len,
140909ba24c1SDouglas Gilbert 						&devip->lu_name);
1410c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1411c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1412760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1413c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1414c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1415760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1416c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1417c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1418c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
14198475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1420c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1421760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1422c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1423c6a44287SMartin K. Petersen 			else
1424c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1425c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1426c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1427c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1428c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1429c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1430c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1431c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1432c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1433c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1434c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1435760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1436760f3b03SDouglas Gilbert 		} else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
1437c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1438760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1439773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1440760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
1441c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1442760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1443760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
1444eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
1445760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b1(&arr[4]);
1446760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
14476014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1448760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
14491da177e4SLinus Torvalds 		} else {
145022017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
14515a09e398SHannes Reinecke 			kfree(arr);
14521da177e4SLinus Torvalds 			return check_condition_result;
14531da177e4SLinus Torvalds 		}
1454773642d9SDouglas Gilbert 		len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
14555a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1456c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
14575a09e398SHannes Reinecke 		kfree(arr);
14585a09e398SHannes Reinecke 		return ret;
14591da177e4SLinus Torvalds 	}
14601da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1461773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1462773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
14631da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
14641da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1465f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1466b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
146770bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1468c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
14691da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1470c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1471e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1472e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1473e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
14749b760fd8SDouglas Gilbert 	/* Use Vendor Specific area to place driver date in ASCII hex */
14759b760fd8SDouglas Gilbert 	memcpy(&arr[36], sdebug_version_date, 8);
14761da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1477760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1478760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1479c65b1445SDouglas Gilbert 	n = 62;
1480760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1481760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1482760f3b03SDouglas Gilbert 		n += 2;
1483760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1484760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1485760f3b03SDouglas Gilbert 		n += 2;
14861da177e4SLinus Torvalds 	}
1487760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
14885a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
14891da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
14905a09e398SHannes Reinecke 	kfree(arr);
14915a09e398SHannes Reinecke 	return ret;
14921da177e4SLinus Torvalds }
14931da177e4SLinus Torvalds 
1494fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1495fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1496fd32119bSDouglas Gilbert 
14971da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp,
14981da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip)
14991da177e4SLinus Torvalds {
15001da177e4SLinus Torvalds 	unsigned char * sbuff;
150101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1502cbf67842SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
15032492fc09STomas Winkler 	bool dsense;
15041da177e4SLinus Torvalds 	int len = 18;
15051da177e4SLinus Torvalds 
1506c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1507c2248fc9SDouglas Gilbert 	dsense = !!(cmd[1] & 1);
1508cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
1509c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1510c2248fc9SDouglas Gilbert 		if (dsense) {
1511c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1512c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1513c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
1514c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
1515c2248fc9SDouglas Gilbert 			len = 8;
1516c65b1445SDouglas Gilbert 		} else {
1517c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1518c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1519c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1520c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
1521c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
1522c65b1445SDouglas Gilbert 		}
1523c65b1445SDouglas Gilbert 	} else {
1524cbf67842SDouglas Gilbert 		memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
1525773642d9SDouglas Gilbert 		if (arr[0] >= 0x70 && dsense == sdebug_dsense)
1526c2248fc9SDouglas Gilbert 			;	/* have sense and formats match */
1527c2248fc9SDouglas Gilbert 		else if (arr[0] <= 0x70) {
1528c2248fc9SDouglas Gilbert 			if (dsense) {
1529c2248fc9SDouglas Gilbert 				memset(arr, 0, 8);
1530c2248fc9SDouglas Gilbert 				arr[0] = 0x72;
1531c2248fc9SDouglas Gilbert 				len = 8;
1532c2248fc9SDouglas Gilbert 			} else {
1533c2248fc9SDouglas Gilbert 				memset(arr, 0, 18);
1534c2248fc9SDouglas Gilbert 				arr[0] = 0x70;
1535c2248fc9SDouglas Gilbert 				arr[7] = 0xa;
1536c2248fc9SDouglas Gilbert 			}
1537c2248fc9SDouglas Gilbert 		} else if (dsense) {
1538c2248fc9SDouglas Gilbert 			memset(arr, 0, 8);
15391da177e4SLinus Torvalds 			arr[0] = 0x72;
15401da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
15411da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
15421da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
15431da177e4SLinus Torvalds 			len = 8;
1544c2248fc9SDouglas Gilbert 		} else {
1545c2248fc9SDouglas Gilbert 			memset(arr, 0, 18);
1546c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1547c2248fc9SDouglas Gilbert 			arr[2] = sbuff[1];
1548c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1549c2248fc9SDouglas Gilbert 			arr[12] = sbuff[1];
1550c2248fc9SDouglas Gilbert 			arr[13] = sbuff[3];
1551c65b1445SDouglas Gilbert 		}
1552c2248fc9SDouglas Gilbert 
1553c65b1445SDouglas Gilbert 	}
1554cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
15551da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
15561da177e4SLinus Torvalds }
15571da177e4SLinus Torvalds 
1558c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp,
1559c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
1560c65b1445SDouglas Gilbert {
156101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1562c4837394SDouglas Gilbert 	int power_cond, stop;
1563c65b1445SDouglas Gilbert 
1564c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1565c65b1445SDouglas Gilbert 	if (power_cond) {
156622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1567c65b1445SDouglas Gilbert 		return check_condition_result;
1568c65b1445SDouglas Gilbert 	}
1569c4837394SDouglas Gilbert 	stop = !(cmd[4] & 1);
1570c4837394SDouglas Gilbert 	atomic_xchg(&devip->stopped, stop);
1571c65b1445SDouglas Gilbert 	return 0;
1572c65b1445SDouglas Gilbert }
1573c65b1445SDouglas Gilbert 
157428898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
157528898873SFUJITA Tomonori {
1576773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1577773642d9SDouglas Gilbert 
1578773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1579773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1580773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
158128898873SFUJITA Tomonori 	else
158228898873SFUJITA Tomonori 		return sdebug_store_sectors;
158328898873SFUJITA Tomonori }
158428898873SFUJITA Tomonori 
15851da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
15861da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp,
15871da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
15881da177e4SLinus Torvalds {
15891da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1590c65b1445SDouglas Gilbert 	unsigned int capac;
15911da177e4SLinus Torvalds 
1592c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
159328898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
15941da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1595c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1596c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1597773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1598773642d9SDouglas Gilbert 	} else
1599773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1600773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
16011da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
16021da177e4SLinus Torvalds }
16031da177e4SLinus Torvalds 
1604c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1605c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp,
1606c65b1445SDouglas Gilbert 			  struct sdebug_dev_info * devip)
1607c65b1445SDouglas Gilbert {
160801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1609c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1610773642d9SDouglas Gilbert 	int alloc_len;
1611c65b1445SDouglas Gilbert 
1612773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1613c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
161428898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1615c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1616773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1617773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1618773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1619773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
162044d92694SMartin K. Petersen 
1621be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
16225b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1623760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1624760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1625760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1626760f3b03SDouglas Gilbert 		 */
1627760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1628760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1629be1dd78dSEric Sandeen 	}
163044d92694SMartin K. Petersen 
1631773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1632c6a44287SMartin K. Petersen 
1633760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1634773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1635c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1636c6a44287SMartin K. Petersen 	}
1637c6a44287SMartin K. Petersen 
1638c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1639c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1640c65b1445SDouglas Gilbert }
1641c65b1445SDouglas Gilbert 
16425a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
16435a09e398SHannes Reinecke 
16445a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp,
16455a09e398SHannes Reinecke 			      struct sdebug_dev_info * devip)
16465a09e398SHannes Reinecke {
164701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
16485a09e398SHannes Reinecke 	unsigned char * arr;
16495a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
16505a09e398SHannes Reinecke 	int n, ret, alen, rlen;
16515a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
16525a09e398SHannes Reinecke 
1653773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
16546f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
16556f3cbf55SDouglas Gilbert 	if (! arr)
16566f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
16575a09e398SHannes Reinecke 	/*
16585a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
16595a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
16605a09e398SHannes Reinecke 	 * So we create two port groups with one port each
16615a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
16625a09e398SHannes Reinecke 	 */
16635a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
16645a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
16655a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
16665a09e398SHannes Reinecke 			(devip->channel & 0x7f);
16675a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
16685a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
16695a09e398SHannes Reinecke 
16705a09e398SHannes Reinecke 	/*
16715a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
16725a09e398SHannes Reinecke 	 */
16735a09e398SHannes Reinecke 	n = 4;
1674b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
16755a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
16765a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
16775a09e398SHannes Reinecke 	} else {
16785a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1679773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
16805a09e398SHannes Reinecke 	}
1681773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1682773642d9SDouglas Gilbert 	n += 2;
16835a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
16845a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
16855a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
16865a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
16875a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
16885a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1689773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1690773642d9SDouglas Gilbert 	n += 2;
16915a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
16925a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1693773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1694773642d9SDouglas Gilbert 	n += 2;
16955a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
16965a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
16975a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
16985a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
16995a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17005a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1701773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1702773642d9SDouglas Gilbert 	n += 2;
17035a09e398SHannes Reinecke 
17045a09e398SHannes Reinecke 	rlen = n - 4;
1705773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
17065a09e398SHannes Reinecke 
17075a09e398SHannes Reinecke 	/*
17085a09e398SHannes Reinecke 	 * Return the smallest value of either
17095a09e398SHannes Reinecke 	 * - The allocated length
17105a09e398SHannes Reinecke 	 * - The constructed command length
17115a09e398SHannes Reinecke 	 * - The maximum array size
17125a09e398SHannes Reinecke 	 */
17135a09e398SHannes Reinecke 	rlen = min(alen,n);
17145a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
17155a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
17165a09e398SHannes Reinecke 	kfree(arr);
17175a09e398SHannes Reinecke 	return ret;
17185a09e398SHannes Reinecke }
17195a09e398SHannes Reinecke 
1720fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1721fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
172238d5c833SDouglas Gilbert {
172338d5c833SDouglas Gilbert 	bool rctd;
172438d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
172538d5c833SDouglas Gilbert 	u16 req_sa, u;
172638d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
172738d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
172838d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
172938d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
173038d5c833SDouglas Gilbert 	u8 *arr;
173138d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
173238d5c833SDouglas Gilbert 
173338d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
173438d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
173538d5c833SDouglas Gilbert 	req_opcode = cmd[3];
173638d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
173738d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
17386d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
173938d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
174038d5c833SDouglas Gilbert 		return check_condition_result;
174138d5c833SDouglas Gilbert 	}
174238d5c833SDouglas Gilbert 	if (alloc_len > 8192)
174338d5c833SDouglas Gilbert 		a_len = 8192;
174438d5c833SDouglas Gilbert 	else
174538d5c833SDouglas Gilbert 		a_len = alloc_len;
174699531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
174738d5c833SDouglas Gilbert 	if (NULL == arr) {
174838d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
174938d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
175038d5c833SDouglas Gilbert 		return check_condition_result;
175138d5c833SDouglas Gilbert 	}
175238d5c833SDouglas Gilbert 	switch (reporting_opts) {
175338d5c833SDouglas Gilbert 	case 0:	/* all commands */
175438d5c833SDouglas Gilbert 		/* count number of commands */
175538d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
175638d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
175738d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
175838d5c833SDouglas Gilbert 				continue;
175938d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
176038d5c833SDouglas Gilbert 		}
176138d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
176238d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
176338d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
176438d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
176538d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
176638d5c833SDouglas Gilbert 				continue;
176738d5c833SDouglas Gilbert 			na = oip->num_attached;
176838d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
176938d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
177038d5c833SDouglas Gilbert 			if (rctd)
177138d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
177238d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
177338d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
177438d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
177538d5c833SDouglas Gilbert 			if (rctd)
177638d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
177738d5c833SDouglas Gilbert 			r_oip = oip;
177838d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
177938d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
178038d5c833SDouglas Gilbert 					continue;
178138d5c833SDouglas Gilbert 				offset += bump;
178238d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
178338d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
178438d5c833SDouglas Gilbert 				if (rctd)
178538d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
178638d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
178738d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
178838d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
178938d5c833SDouglas Gilbert 						   arr + offset + 6);
179038d5c833SDouglas Gilbert 				if (rctd)
179138d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
179238d5c833SDouglas Gilbert 							   arr + offset + 8);
179338d5c833SDouglas Gilbert 			}
179438d5c833SDouglas Gilbert 			oip = r_oip;
179538d5c833SDouglas Gilbert 			offset += bump;
179638d5c833SDouglas Gilbert 		}
179738d5c833SDouglas Gilbert 		break;
179838d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
179938d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
180038d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
180138d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
180238d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
180338d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
180438d5c833SDouglas Gilbert 			supp = 1;
180538d5c833SDouglas Gilbert 			offset = 4;
180638d5c833SDouglas Gilbert 		} else {
180738d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
180838d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
180938d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
181038d5c833SDouglas Gilbert 							     2, 2);
181138d5c833SDouglas Gilbert 					kfree(arr);
181238d5c833SDouglas Gilbert 					return check_condition_result;
181338d5c833SDouglas Gilbert 				}
181438d5c833SDouglas Gilbert 				req_sa = 0;
181538d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
181638d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
181738d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
181838d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
181938d5c833SDouglas Gilbert 				return check_condition_result;
182038d5c833SDouglas Gilbert 			}
182138d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
182238d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
182338d5c833SDouglas Gilbert 				supp = 3;
182438d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
182538d5c833SDouglas Gilbert 				na = oip->num_attached;
182638d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
182738d5c833SDouglas Gilbert 				     ++k, ++oip) {
182838d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
182938d5c833SDouglas Gilbert 						break;
183038d5c833SDouglas Gilbert 				}
183138d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
183238d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
183338d5c833SDouglas Gilbert 				na = oip->num_attached;
183438d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
183538d5c833SDouglas Gilbert 				     ++k, ++oip) {
183638d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
183738d5c833SDouglas Gilbert 						break;
183838d5c833SDouglas Gilbert 				}
183938d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
184038d5c833SDouglas Gilbert 			} else
184138d5c833SDouglas Gilbert 				supp = 3;
184238d5c833SDouglas Gilbert 			if (3 == supp) {
184338d5c833SDouglas Gilbert 				u = oip->len_mask[0];
184438d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
184538d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
184638d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
184738d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
184838d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
184938d5c833SDouglas Gilbert 				offset = 4 + u;
185038d5c833SDouglas Gilbert 			} else
185138d5c833SDouglas Gilbert 				offset = 4;
185238d5c833SDouglas Gilbert 		}
185338d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
185438d5c833SDouglas Gilbert 		if (rctd) {
185538d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
185638d5c833SDouglas Gilbert 			offset += 12;
185738d5c833SDouglas Gilbert 		}
185838d5c833SDouglas Gilbert 		break;
185938d5c833SDouglas Gilbert 	default:
186038d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
186138d5c833SDouglas Gilbert 		kfree(arr);
186238d5c833SDouglas Gilbert 		return check_condition_result;
186338d5c833SDouglas Gilbert 	}
186438d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
186538d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
186638d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
186738d5c833SDouglas Gilbert 	kfree(arr);
186838d5c833SDouglas Gilbert 	return errsts;
186938d5c833SDouglas Gilbert }
187038d5c833SDouglas Gilbert 
1871fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1872fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
187338d5c833SDouglas Gilbert {
187438d5c833SDouglas Gilbert 	bool repd;
187538d5c833SDouglas Gilbert 	u32 alloc_len, len;
187638d5c833SDouglas Gilbert 	u8 arr[16];
187738d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
187838d5c833SDouglas Gilbert 
187938d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
188038d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
188138d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
188238d5c833SDouglas Gilbert 	if (alloc_len < 4) {
188338d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
188438d5c833SDouglas Gilbert 		return check_condition_result;
188538d5c833SDouglas Gilbert 	}
188638d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
188738d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
188838d5c833SDouglas Gilbert 	if (repd) {
188938d5c833SDouglas Gilbert 		arr[3] = 0xc;
189038d5c833SDouglas Gilbert 		len = 16;
189138d5c833SDouglas Gilbert 	} else
189238d5c833SDouglas Gilbert 		len = 4;
189338d5c833SDouglas Gilbert 
189438d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
189538d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
189638d5c833SDouglas Gilbert }
189738d5c833SDouglas Gilbert 
18981da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
18991da177e4SLinus Torvalds 
19001da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
19011da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
19021da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
19031da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
19041da177e4SLinus Torvalds 
19051da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
19061da177e4SLinus Torvalds 	if (1 == pcontrol)
19071da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
19081da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
19091da177e4SLinus Torvalds }
19101da177e4SLinus Torvalds 
19111da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
19121da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
19131da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
19141da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
19151da177e4SLinus Torvalds 
19161da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
19171da177e4SLinus Torvalds 	if (1 == pcontrol)
19181da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
19191da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
19201da177e4SLinus Torvalds }
19211da177e4SLinus Torvalds 
19221da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target)
19231da177e4SLinus Torvalds {       /* Format device page for mode_sense */
19241da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
19251da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
19261da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
19271da177e4SLinus Torvalds 
19281da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
1929773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
1930773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
1931773642d9SDouglas Gilbert 	if (sdebug_removable)
19321da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
19331da177e4SLinus Torvalds 	if (1 == pcontrol)
19341da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
19351da177e4SLinus Torvalds 	return sizeof(format_pg);
19361da177e4SLinus Torvalds }
19371da177e4SLinus Torvalds 
1938fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1939fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1940fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
1941fd32119bSDouglas Gilbert 
19421da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
19431da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
1944cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1945cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1946cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
19471da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
19481da177e4SLinus Torvalds 
1949773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
1950cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
19511da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
19521da177e4SLinus Torvalds 	if (1 == pcontrol)
1953cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1954cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
1955cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
19561da177e4SLinus Torvalds 	return sizeof(caching_pg);
19571da177e4SLinus Torvalds }
19581da177e4SLinus Torvalds 
1959fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
1960fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
1961fd32119bSDouglas Gilbert 
19621da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
19631da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
1964c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1965c65b1445SDouglas Gilbert 				        0, 0, 0, 0};
1966c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
19671da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
19681da177e4SLinus Torvalds 
1969773642d9SDouglas Gilbert 	if (sdebug_dsense)
19701da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
1971c65b1445SDouglas Gilbert 	else
1972c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
1973c6a44287SMartin K. Petersen 
1974773642d9SDouglas Gilbert 	if (sdebug_ato)
1975c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1976c6a44287SMartin K. Petersen 
19771da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
19781da177e4SLinus Torvalds 	if (1 == pcontrol)
1979c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1980c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1981c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
19821da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
19831da177e4SLinus Torvalds }
19841da177e4SLinus Torvalds 
1985c65b1445SDouglas Gilbert 
19861da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
19871da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
1988c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
19891da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
1990c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1991c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
1992c65b1445SDouglas Gilbert 
19931da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
19941da177e4SLinus Torvalds 	if (1 == pcontrol)
1995c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1996c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1997c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
19981da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
19991da177e4SLinus Torvalds }
20001da177e4SLinus Torvalds 
2001c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
2002c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2003c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2004c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2005c65b1445SDouglas Gilbert 
2006c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2007c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2008c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2009c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2010c65b1445SDouglas Gilbert }
2011c65b1445SDouglas Gilbert 
2012c65b1445SDouglas Gilbert 
2013c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
2014c65b1445SDouglas Gilbert 			      int target_dev_id)
2015c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2016c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2017c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2018773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2019773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2020c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2021c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2022c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2023c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2024773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2025773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2026c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2027c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2028c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2029c65b1445SDouglas Gilbert 		};
2030c65b1445SDouglas Gilbert 	int port_a, port_b;
2031c65b1445SDouglas Gilbert 
20321b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
20331b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
20341b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
20351b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2036c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2037c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2038c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2039773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2040773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2041c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2042c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2043c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2044c65b1445SDouglas Gilbert }
2045c65b1445SDouglas Gilbert 
2046c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
2047c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2048c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2049c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2050c65b1445SDouglas Gilbert 		};
2051c65b1445SDouglas Gilbert 
2052c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2053c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2054c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2055c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2056c65b1445SDouglas Gilbert }
2057c65b1445SDouglas Gilbert 
20581da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
20591da177e4SLinus Torvalds 
2060fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2061fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
20621da177e4SLinus Torvalds {
206323183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
20641da177e4SLinus Torvalds 	unsigned char dev_spec;
2065760f3b03SDouglas Gilbert 	int alloc_len, offset, len, target_dev_id;
2066c2248fc9SDouglas Gilbert 	int target = scp->device->id;
20671da177e4SLinus Torvalds 	unsigned char * ap;
20681da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
206901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2070760f3b03SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, bad_pcode;
20711da177e4SLinus Torvalds 
2072760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
20731da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
20741da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
20751da177e4SLinus Torvalds 	subpcode = cmd[3];
20761da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2077760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2078760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
2079760f3b03SDouglas Gilbert 	if (is_disk && !dbd)
208023183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
208123183910SDouglas Gilbert 	else
208223183910SDouglas Gilbert 		bd_len = 0;
2083773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
20841da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
20851da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2086cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
20871da177e4SLinus Torvalds 		return check_condition_result;
20881da177e4SLinus Torvalds 	}
2089c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2090c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2091b01f6f83SDouglas Gilbert 	/* for disks set DPOFUA bit and clear write protect (WP) bit */
2092760f3b03SDouglas Gilbert 	if (is_disk)
2093b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
209423183910SDouglas Gilbert 	else
209523183910SDouglas Gilbert 		dev_spec = 0x0;
20961da177e4SLinus Torvalds 	if (msense_6) {
20971da177e4SLinus Torvalds 		arr[2] = dev_spec;
209823183910SDouglas Gilbert 		arr[3] = bd_len;
20991da177e4SLinus Torvalds 		offset = 4;
21001da177e4SLinus Torvalds 	} else {
21011da177e4SLinus Torvalds 		arr[3] = dev_spec;
210223183910SDouglas Gilbert 		if (16 == bd_len)
210323183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
210423183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
21051da177e4SLinus Torvalds 		offset = 8;
21061da177e4SLinus Torvalds 	}
21071da177e4SLinus Torvalds 	ap = arr + offset;
210828898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
210928898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
211028898873SFUJITA Tomonori 
211123183910SDouglas Gilbert 	if (8 == bd_len) {
2112773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2113773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2114773642d9SDouglas Gilbert 		else
2115773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2116773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
211723183910SDouglas Gilbert 		offset += bd_len;
211823183910SDouglas Gilbert 		ap = arr + offset;
211923183910SDouglas Gilbert 	} else if (16 == bd_len) {
2120773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2121773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
212223183910SDouglas Gilbert 		offset += bd_len;
212323183910SDouglas Gilbert 		ap = arr + offset;
212423183910SDouglas Gilbert 	}
21251da177e4SLinus Torvalds 
2126c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2127c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
212822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
21291da177e4SLinus Torvalds 		return check_condition_result;
21301da177e4SLinus Torvalds 	}
2131760f3b03SDouglas Gilbert 	bad_pcode = false;
2132760f3b03SDouglas Gilbert 
21331da177e4SLinus Torvalds 	switch (pcode) {
21341da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
21351da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
21361da177e4SLinus Torvalds 		offset += len;
21371da177e4SLinus Torvalds 		break;
21381da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
21391da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
21401da177e4SLinus Torvalds 		offset += len;
21411da177e4SLinus Torvalds 		break;
21421da177e4SLinus Torvalds         case 0x3:       /* Format device page, direct access */
2143760f3b03SDouglas Gilbert 		if (is_disk) {
21441da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
21451da177e4SLinus Torvalds 			offset += len;
2146760f3b03SDouglas Gilbert 		} else
2147760f3b03SDouglas Gilbert 			bad_pcode = true;
21481da177e4SLinus Torvalds                 break;
21491da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2150760f3b03SDouglas Gilbert 		if (is_disk) {
21511da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
21521da177e4SLinus Torvalds 			offset += len;
2153760f3b03SDouglas Gilbert 		} else
2154760f3b03SDouglas Gilbert 			bad_pcode = true;
21551da177e4SLinus Torvalds 		break;
21561da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
21571da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
21581da177e4SLinus Torvalds 		offset += len;
21591da177e4SLinus Torvalds 		break;
2160c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2161c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
216222017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2163c65b1445SDouglas Gilbert 			return check_condition_result;
2164c65b1445SDouglas Gilbert 	        }
2165c65b1445SDouglas Gilbert 		len = 0;
2166c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2167c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2168c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2169c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2170c65b1445SDouglas Gilbert 						  target_dev_id);
2171c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2172c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2173c65b1445SDouglas Gilbert 		offset += len;
2174c65b1445SDouglas Gilbert 		break;
21751da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
21761da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
21771da177e4SLinus Torvalds 		offset += len;
21781da177e4SLinus Torvalds 		break;
21791da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2180c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
21811da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
21821da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2183760f3b03SDouglas Gilbert 			if (is_disk) {
2184760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2185760f3b03SDouglas Gilbert 						      target);
2186760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2187760f3b03SDouglas Gilbert 						       target);
2188760f3b03SDouglas Gilbert 			}
21891da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2190c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2191c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2192c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2193c65b1445SDouglas Gilbert 						  target, target_dev_id);
2194c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2195c65b1445SDouglas Gilbert 			}
21961da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2197760f3b03SDouglas Gilbert 			offset += len;
2198c65b1445SDouglas Gilbert 		} else {
219922017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2200c65b1445SDouglas Gilbert 			return check_condition_result;
2201c65b1445SDouglas Gilbert                 }
22021da177e4SLinus Torvalds 		break;
22031da177e4SLinus Torvalds 	default:
2204760f3b03SDouglas Gilbert 		bad_pcode = true;
2205760f3b03SDouglas Gilbert 		break;
2206760f3b03SDouglas Gilbert 	}
2207760f3b03SDouglas Gilbert 	if (bad_pcode) {
220822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
22091da177e4SLinus Torvalds 		return check_condition_result;
22101da177e4SLinus Torvalds 	}
22111da177e4SLinus Torvalds 	if (msense_6)
22121da177e4SLinus Torvalds 		arr[0] = offset - 1;
2213773642d9SDouglas Gilbert 	else
2214773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
22151da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
22161da177e4SLinus Torvalds }
22171da177e4SLinus Torvalds 
2218c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2219c65b1445SDouglas Gilbert 
2220fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2221fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2222c65b1445SDouglas Gilbert {
2223c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2224c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2225c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
222601123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2227c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2228c65b1445SDouglas Gilbert 
2229c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2230c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2231c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2232773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2233c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
223422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2235c65b1445SDouglas Gilbert 		return check_condition_result;
2236c65b1445SDouglas Gilbert 	}
2237c65b1445SDouglas Gilbert         res = fetch_to_dev_buffer(scp, arr, param_len);
2238c65b1445SDouglas Gilbert         if (-1 == res)
2239773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2240773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2241cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2242cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2243cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2244773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2245773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
224623183910SDouglas Gilbert 	if (md_len > 2) {
224722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2248c65b1445SDouglas Gilbert 		return check_condition_result;
2249c65b1445SDouglas Gilbert 	}
2250c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2251c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2252c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2253c65b1445SDouglas Gilbert 	if (ps) {
225422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2255c65b1445SDouglas Gilbert 		return check_condition_result;
2256c65b1445SDouglas Gilbert 	}
2257c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2258773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2259c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2260c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2261cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2262c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2263c65b1445SDouglas Gilbert 		return check_condition_result;
2264c65b1445SDouglas Gilbert 	}
2265c65b1445SDouglas Gilbert 	switch (mpage) {
2266cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2267cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2268cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2269cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2270cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2271cbf67842SDouglas Gilbert 		}
2272cbf67842SDouglas Gilbert 		break;
2273c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2274c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2275c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2276c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
2277773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2278cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2279c65b1445SDouglas Gilbert 		}
2280c65b1445SDouglas Gilbert 		break;
2281c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2282c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2283c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2284c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2285cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2286c65b1445SDouglas Gilbert 		}
2287c65b1445SDouglas Gilbert 		break;
2288c65b1445SDouglas Gilbert 	default:
2289c65b1445SDouglas Gilbert 		break;
2290c65b1445SDouglas Gilbert 	}
229122017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2292c65b1445SDouglas Gilbert 	return check_condition_result;
2293cbf67842SDouglas Gilbert set_mode_changed_ua:
2294cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2295cbf67842SDouglas Gilbert 	return 0;
2296c65b1445SDouglas Gilbert }
2297c65b1445SDouglas Gilbert 
2298c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr)
2299c65b1445SDouglas Gilbert {
2300c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2301c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2302c65b1445SDouglas Gilbert 		};
2303c65b1445SDouglas Gilbert 
2304c65b1445SDouglas Gilbert         memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2305c65b1445SDouglas Gilbert         return sizeof(temp_l_pg);
2306c65b1445SDouglas Gilbert }
2307c65b1445SDouglas Gilbert 
2308c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr)
2309c65b1445SDouglas Gilbert {
2310c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2311c65b1445SDouglas Gilbert 		};
2312c65b1445SDouglas Gilbert 
2313c65b1445SDouglas Gilbert         memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2314c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2315c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2316c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2317c65b1445SDouglas Gilbert 	}
2318c65b1445SDouglas Gilbert         return sizeof(ie_l_pg);
2319c65b1445SDouglas Gilbert }
2320c65b1445SDouglas Gilbert 
2321c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2322c65b1445SDouglas Gilbert 
2323c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp,
2324c65b1445SDouglas Gilbert                           struct sdebug_dev_info * devip)
2325c65b1445SDouglas Gilbert {
2326ab17241cSBart Van Assche 	int ppc, sp, pcode, subpcode, alloc_len, len, n;
2327c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
232801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2329c65b1445SDouglas Gilbert 
2330c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2331c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2332c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2333c65b1445SDouglas Gilbert 	if (ppc || sp) {
233422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2335c65b1445SDouglas Gilbert 		return check_condition_result;
2336c65b1445SDouglas Gilbert 	}
2337c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
233823183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2339773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2340c65b1445SDouglas Gilbert 	arr[0] = pcode;
234123183910SDouglas Gilbert 	if (0 == subpcode) {
2342c65b1445SDouglas Gilbert 		switch (pcode) {
2343c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2344c65b1445SDouglas Gilbert 			n = 4;
2345c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2346c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2347c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2348c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2349c65b1445SDouglas Gilbert 			break;
2350c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2351c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2352c65b1445SDouglas Gilbert 			break;
2353c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2354c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2355c65b1445SDouglas Gilbert 			break;
2356c65b1445SDouglas Gilbert 		default:
235722017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2358c65b1445SDouglas Gilbert 			return check_condition_result;
2359c65b1445SDouglas Gilbert 		}
236023183910SDouglas Gilbert 	} else if (0xff == subpcode) {
236123183910SDouglas Gilbert 		arr[0] |= 0x40;
236223183910SDouglas Gilbert 		arr[1] = subpcode;
236323183910SDouglas Gilbert 		switch (pcode) {
236423183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
236523183910SDouglas Gilbert 			n = 4;
236623183910SDouglas Gilbert 			arr[n++] = 0x0;
236723183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
236823183910SDouglas Gilbert 			arr[n++] = 0x0;
236923183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
237023183910SDouglas Gilbert 			arr[n++] = 0xd;
237123183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
237223183910SDouglas Gilbert 			arr[n++] = 0x2f;
237323183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
237423183910SDouglas Gilbert 			arr[3] = n - 4;
237523183910SDouglas Gilbert 			break;
237623183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
237723183910SDouglas Gilbert 			n = 4;
237823183910SDouglas Gilbert 			arr[n++] = 0xd;
237923183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
238023183910SDouglas Gilbert 			arr[3] = n - 4;
238123183910SDouglas Gilbert 			break;
238223183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
238323183910SDouglas Gilbert 			n = 4;
238423183910SDouglas Gilbert 			arr[n++] = 0x2f;
238523183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
238623183910SDouglas Gilbert 			arr[3] = n - 4;
238723183910SDouglas Gilbert 			break;
238823183910SDouglas Gilbert 		default:
238922017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
239023183910SDouglas Gilbert 			return check_condition_result;
239123183910SDouglas Gilbert 		}
239223183910SDouglas Gilbert 	} else {
239322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
239423183910SDouglas Gilbert 		return check_condition_result;
239523183910SDouglas Gilbert 	}
2396773642d9SDouglas Gilbert 	len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
2397c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
2398c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
2399c65b1445SDouglas Gilbert }
2400c65b1445SDouglas Gilbert 
2401cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp,
240219789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
24031da177e4SLinus Torvalds {
2404c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
240522017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
24061da177e4SLinus Torvalds 		return check_condition_result;
24071da177e4SLinus Torvalds 	}
2408c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2409c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
241022017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2411cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2412c65b1445SDouglas Gilbert 		return check_condition_result;
2413c65b1445SDouglas Gilbert 	}
241419789100SFUJITA Tomonori 	return 0;
241519789100SFUJITA Tomonori }
241619789100SFUJITA Tomonori 
2417a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
2418fd32119bSDouglas Gilbert static int do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num,
2419fd32119bSDouglas Gilbert 			    bool do_write)
242019789100SFUJITA Tomonori {
242119789100SFUJITA Tomonori 	int ret;
2422c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2423a4517511SAkinobu Mita 	struct scsi_data_buffer *sdb;
2424a4517511SAkinobu Mita 	enum dma_data_direction dir;
242519789100SFUJITA Tomonori 
2426c2248fc9SDouglas Gilbert 	if (do_write) {
2427a4517511SAkinobu Mita 		sdb = scsi_out(scmd);
2428a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
2429a4517511SAkinobu Mita 	} else {
2430a4517511SAkinobu Mita 		sdb = scsi_in(scmd);
2431a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2432a4517511SAkinobu Mita 	}
2433a4517511SAkinobu Mita 
2434a4517511SAkinobu Mita 	if (!sdb->length)
2435a4517511SAkinobu Mita 		return 0;
2436a4517511SAkinobu Mita 	if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2437a4517511SAkinobu Mita 		return -1;
243819789100SFUJITA Tomonori 
243919789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
244019789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
244119789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
244219789100SFUJITA Tomonori 
2443386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2444773642d9SDouglas Gilbert 		   fake_storep + (block * sdebug_sector_size),
2445773642d9SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, 0, do_write);
2446773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2447a4517511SAkinobu Mita 		return ret;
2448a4517511SAkinobu Mita 
2449a4517511SAkinobu Mita 	if (rest) {
2450386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2451773642d9SDouglas Gilbert 			    fake_storep, rest * sdebug_sector_size,
2452773642d9SDouglas Gilbert 			    (num - rest) * sdebug_sector_size, do_write);
2453a4517511SAkinobu Mita 	}
245419789100SFUJITA Tomonori 
245519789100SFUJITA Tomonori 	return ret;
245619789100SFUJITA Tomonori }
245719789100SFUJITA Tomonori 
245838d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of
245938d5c833SDouglas Gilbert  * arr into fake_store(lba,num) and return true. If comparison fails then
246038d5c833SDouglas Gilbert  * return false. */
2461fd32119bSDouglas Gilbert static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
246238d5c833SDouglas Gilbert {
246338d5c833SDouglas Gilbert 	bool res;
246438d5c833SDouglas Gilbert 	u64 block, rest = 0;
246538d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2466773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
246738d5c833SDouglas Gilbert 
246838d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
246938d5c833SDouglas Gilbert 	if (block + num > store_blks)
247038d5c833SDouglas Gilbert 		rest = block + num - store_blks;
247138d5c833SDouglas Gilbert 
247238d5c833SDouglas Gilbert 	res = !memcmp(fake_storep + (block * lb_size), arr,
247338d5c833SDouglas Gilbert 		      (num - rest) * lb_size);
247438d5c833SDouglas Gilbert 	if (!res)
247538d5c833SDouglas Gilbert 		return res;
247638d5c833SDouglas Gilbert 	if (rest)
247738d5c833SDouglas Gilbert 		res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
247838d5c833SDouglas Gilbert 			     rest * lb_size);
247938d5c833SDouglas Gilbert 	if (!res)
248038d5c833SDouglas Gilbert 		return res;
248138d5c833SDouglas Gilbert 	arr += num * lb_size;
248238d5c833SDouglas Gilbert 	memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
248338d5c833SDouglas Gilbert 	if (rest)
248438d5c833SDouglas Gilbert 		memcpy(fake_storep, arr + ((num - rest) * lb_size),
248538d5c833SDouglas Gilbert 		       rest * lb_size);
248638d5c833SDouglas Gilbert 	return res;
248738d5c833SDouglas Gilbert }
248838d5c833SDouglas Gilbert 
248951d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2490beb40ea4SAkinobu Mita {
249151d648afSAkinobu Mita 	__be16 csum;
2492beb40ea4SAkinobu Mita 
2493773642d9SDouglas Gilbert 	if (sdebug_guard)
249451d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
249551d648afSAkinobu Mita 	else
2496beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
249751d648afSAkinobu Mita 
2498beb40ea4SAkinobu Mita 	return csum;
2499beb40ea4SAkinobu Mita }
2500beb40ea4SAkinobu Mita 
25016ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
2502beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
2503beb40ea4SAkinobu Mita {
2504773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
2505beb40ea4SAkinobu Mita 
2506beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
2507c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
2508beb40ea4SAkinobu Mita 			(unsigned long)sector,
2509beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
2510beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
2511beb40ea4SAkinobu Mita 		return 0x01;
2512beb40ea4SAkinobu Mita 	}
25138475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
2514beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
2515c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2516c1287970STomas Winkler 			(unsigned long)sector);
2517beb40ea4SAkinobu Mita 		return 0x03;
2518beb40ea4SAkinobu Mita 	}
25198475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2520beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
2521c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2522c1287970STomas Winkler 			(unsigned long)sector);
2523beb40ea4SAkinobu Mita 		return 0x03;
2524beb40ea4SAkinobu Mita 	}
2525beb40ea4SAkinobu Mita 	return 0;
2526beb40ea4SAkinobu Mita }
2527beb40ea4SAkinobu Mita 
2528bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
252965f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
2530c6a44287SMartin K. Petersen {
2531be4e11beSAkinobu Mita 	size_t resid;
2532c6a44287SMartin K. Petersen 	void *paddr;
253314faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
2534be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
2535c6a44287SMartin K. Petersen 
2536e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
2537e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
2538c6a44287SMartin K. Petersen 
2539be4e11beSAkinobu Mita 	sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2540be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2541be4e11beSAkinobu Mita 			(read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2542be4e11beSAkinobu Mita 
2543be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
2544be4e11beSAkinobu Mita 		size_t len = min(miter.length, resid);
254514faa944SAkinobu Mita 		void *start = dif_store(sector);
2546be4e11beSAkinobu Mita 		size_t rest = 0;
254714faa944SAkinobu Mita 
254814faa944SAkinobu Mita 		if (dif_store_end < start + len)
254914faa944SAkinobu Mita 			rest = start + len - dif_store_end;
2550c6a44287SMartin K. Petersen 
2551be4e11beSAkinobu Mita 		paddr = miter.addr;
255214faa944SAkinobu Mita 
255365f72f2aSAkinobu Mita 		if (read)
255465f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
255565f72f2aSAkinobu Mita 		else
255665f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
255765f72f2aSAkinobu Mita 
255865f72f2aSAkinobu Mita 		if (rest) {
255965f72f2aSAkinobu Mita 			if (read)
256014faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
256165f72f2aSAkinobu Mita 			else
256265f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
256365f72f2aSAkinobu Mita 		}
2564c6a44287SMartin K. Petersen 
2565e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
2566c6a44287SMartin K. Petersen 		resid -= len;
2567c6a44287SMartin K. Petersen 	}
2568be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
2569bb8c063cSAkinobu Mita }
2570c6a44287SMartin K. Petersen 
2571bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2572bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
2573bb8c063cSAkinobu Mita {
2574bb8c063cSAkinobu Mita 	unsigned int i;
25756ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
2576bb8c063cSAkinobu Mita 	sector_t sector;
2577bb8c063cSAkinobu Mita 
2578c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
2579bb8c063cSAkinobu Mita 		int ret;
2580bb8c063cSAkinobu Mita 
2581bb8c063cSAkinobu Mita 		sector = start_sec + i;
2582bb8c063cSAkinobu Mita 		sdt = dif_store(sector);
2583bb8c063cSAkinobu Mita 
258451d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
2585bb8c063cSAkinobu Mita 			continue;
2586bb8c063cSAkinobu Mita 
2587bb8c063cSAkinobu Mita 		ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2588bb8c063cSAkinobu Mita 		if (ret) {
2589bb8c063cSAkinobu Mita 			dif_errors++;
2590bb8c063cSAkinobu Mita 			return ret;
2591bb8c063cSAkinobu Mita 		}
2592bb8c063cSAkinobu Mita 	}
2593bb8c063cSAkinobu Mita 
259465f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, true);
2595c6a44287SMartin K. Petersen 	dix_reads++;
2596c6a44287SMartin K. Petersen 
2597c6a44287SMartin K. Petersen 	return 0;
2598c6a44287SMartin K. Petersen }
2599c6a44287SMartin K. Petersen 
2600fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
260119789100SFUJITA Tomonori {
2602c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2603c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
2604c2248fc9SDouglas Gilbert 	u64 lba;
2605c2248fc9SDouglas Gilbert 	u32 num;
2606c2248fc9SDouglas Gilbert 	u32 ei_lba;
260719789100SFUJITA Tomonori 	unsigned long iflags;
260819789100SFUJITA Tomonori 	int ret;
2609c2248fc9SDouglas Gilbert 	bool check_prot;
261019789100SFUJITA Tomonori 
2611c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2612c2248fc9SDouglas Gilbert 	case READ_16:
2613c2248fc9SDouglas Gilbert 		ei_lba = 0;
2614c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2615c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2616c2248fc9SDouglas Gilbert 		check_prot = true;
2617c2248fc9SDouglas Gilbert 		break;
2618c2248fc9SDouglas Gilbert 	case READ_10:
2619c2248fc9SDouglas Gilbert 		ei_lba = 0;
2620c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2621c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2622c2248fc9SDouglas Gilbert 		check_prot = true;
2623c2248fc9SDouglas Gilbert 		break;
2624c2248fc9SDouglas Gilbert 	case READ_6:
2625c2248fc9SDouglas Gilbert 		ei_lba = 0;
2626c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2627c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2628c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2629c2248fc9SDouglas Gilbert 		check_prot = true;
2630c2248fc9SDouglas Gilbert 		break;
2631c2248fc9SDouglas Gilbert 	case READ_12:
2632c2248fc9SDouglas Gilbert 		ei_lba = 0;
2633c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2634c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2635c2248fc9SDouglas Gilbert 		check_prot = true;
2636c2248fc9SDouglas Gilbert 		break;
2637c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
2638c2248fc9SDouglas Gilbert 		ei_lba = 0;
2639c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2640c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2641c2248fc9SDouglas Gilbert 		check_prot = false;
2642c2248fc9SDouglas Gilbert 		break;
2643c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
2644c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2645c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2646c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2647c2248fc9SDouglas Gilbert 		check_prot = false;
2648c2248fc9SDouglas Gilbert 		break;
2649c2248fc9SDouglas Gilbert 	}
2650f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
26518475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2652c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2653c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2654c2248fc9SDouglas Gilbert 			return check_condition_result;
2655c2248fc9SDouglas Gilbert 		}
26568475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
26578475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
2658c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2659c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2660c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2661c2248fc9SDouglas Gilbert 	}
2662f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
2663c4837394SDouglas Gilbert 		sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
2664c2248fc9SDouglas Gilbert 
2665c4837394SDouglas Gilbert 		if (sqcp) {
2666c4837394SDouglas Gilbert 			if (sqcp->inj_short)
2667c2248fc9SDouglas Gilbert 				num /= 2;
2668c2248fc9SDouglas Gilbert 		}
2669c4837394SDouglas Gilbert 	} else
2670c4837394SDouglas Gilbert 		sqcp = NULL;
2671c2248fc9SDouglas Gilbert 
2672c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2673f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
2674c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2675c2248fc9SDouglas Gilbert 		return check_condition_result;
2676c2248fc9SDouglas Gilbert 	}
2677c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2678f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
2679c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2680c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2681c2248fc9SDouglas Gilbert 		return check_condition_result;
2682c2248fc9SDouglas Gilbert 	}
268319789100SFUJITA Tomonori 
2684f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
268532f7ef73SDouglas Gilbert 		     (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
2686f46eb0e9SDouglas Gilbert 		     ((lba + num) > OPT_MEDIUM_ERR_ADDR))) {
2687c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
2688c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
2689c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
2690c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2691c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
269232f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
269332f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
2694c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
2695c65b1445SDouglas Gilbert 		}
2696c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
26971da177e4SLinus Torvalds 		return check_condition_result;
26981da177e4SLinus Torvalds 	}
2699c6a44287SMartin K. Petersen 
27006c78cc06SAkinobu Mita 	read_lock_irqsave(&atomic_rw, iflags);
27016c78cc06SAkinobu Mita 
2702c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2703f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
2704c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
2705c6a44287SMartin K. Petersen 
2706c6a44287SMartin K. Petersen 		if (prot_ret) {
27076c78cc06SAkinobu Mita 			read_unlock_irqrestore(&atomic_rw, iflags);
2708c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
2709c6a44287SMartin K. Petersen 			return illegal_condition_result;
2710c6a44287SMartin K. Petersen 		}
2711c6a44287SMartin K. Petersen 	}
2712c6a44287SMartin K. Petersen 
2713c2248fc9SDouglas Gilbert 	ret = do_device_access(scp, lba, num, false);
27141da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
2715f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
2716a4517511SAkinobu Mita 		return DID_ERROR << 16;
2717a4517511SAkinobu Mita 
2718c2248fc9SDouglas Gilbert 	scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
2719a4517511SAkinobu Mita 
2720c4837394SDouglas Gilbert 	if (unlikely(sqcp)) {
2721c4837394SDouglas Gilbert 		if (sqcp->inj_recovered) {
2722c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
2723c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
2724c2248fc9SDouglas Gilbert 			return check_condition_result;
2725c4837394SDouglas Gilbert 		} else if (sqcp->inj_transport) {
2726c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND,
2727c2248fc9SDouglas Gilbert 					TRANSPORT_PROBLEM, ACK_NAK_TO);
2728c2248fc9SDouglas Gilbert 			return check_condition_result;
2729c4837394SDouglas Gilbert 		} else if (sqcp->inj_dif) {
2730c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
2731c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2732c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2733c4837394SDouglas Gilbert 		} else if (sqcp->inj_dix) {
2734c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2735c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2736c2248fc9SDouglas Gilbert 		}
2737c2248fc9SDouglas Gilbert 	}
2738a4517511SAkinobu Mita 	return 0;
27391da177e4SLinus Torvalds }
27401da177e4SLinus Torvalds 
274158a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len)
2742c6a44287SMartin K. Petersen {
2743cbf67842SDouglas Gilbert 	int i, j, n;
2744c6a44287SMartin K. Petersen 
2745cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
2746c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
2747cbf67842SDouglas Gilbert 		char b[128];
2748c6a44287SMartin K. Petersen 
2749cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
2750c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
2751c6a44287SMartin K. Petersen 
2752cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
2753cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2754cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
2755cbf67842SDouglas Gilbert 			else
2756cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2757cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
2758cbf67842SDouglas Gilbert 		}
2759cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
2760c6a44287SMartin K. Petersen 	}
2761c6a44287SMartin K. Petersen }
2762c6a44287SMartin K. Petersen 
2763c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
2764395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
2765c6a44287SMartin K. Petersen {
2766be4e11beSAkinobu Mita 	int ret;
27676ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
2768be4e11beSAkinobu Mita 	void *daddr;
276965f72f2aSAkinobu Mita 	sector_t sector = start_sec;
2770c6a44287SMartin K. Petersen 	int ppage_offset;
2771be4e11beSAkinobu Mita 	int dpage_offset;
2772be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
2773be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
2774c6a44287SMartin K. Petersen 
2775c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
2776c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2777c6a44287SMartin K. Petersen 
2778be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2779be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
2780be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2781be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2782be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2783c6a44287SMartin K. Petersen 
2784be4e11beSAkinobu Mita 	/* For each protection page */
2785be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
2786be4e11beSAkinobu Mita 		dpage_offset = 0;
2787be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
2788be4e11beSAkinobu Mita 			ret = 0x01;
2789be4e11beSAkinobu Mita 			goto out;
2790c6a44287SMartin K. Petersen 		}
2791c6a44287SMartin K. Petersen 
2792be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
27936ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
2794be4e11beSAkinobu Mita 			/* If we're at the end of the current
2795be4e11beSAkinobu Mita 			 * data page advance to the next one
2796be4e11beSAkinobu Mita 			 */
2797be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
2798be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
2799be4e11beSAkinobu Mita 					ret = 0x01;
2800be4e11beSAkinobu Mita 					goto out;
2801be4e11beSAkinobu Mita 				}
2802be4e11beSAkinobu Mita 				dpage_offset = 0;
2803be4e11beSAkinobu Mita 			}
2804c6a44287SMartin K. Petersen 
2805be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
2806be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
2807be4e11beSAkinobu Mita 
2808be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
2809beb40ea4SAkinobu Mita 			if (ret) {
2810773642d9SDouglas Gilbert 				dump_sector(daddr, sdebug_sector_size);
2811395cef03SMartin K. Petersen 				goto out;
2812395cef03SMartin K. Petersen 			}
2813395cef03SMartin K. Petersen 
2814c6a44287SMartin K. Petersen 			sector++;
2815395cef03SMartin K. Petersen 			ei_lba++;
2816773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
2817c6a44287SMartin K. Petersen 		}
2818be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
2819be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
2820c6a44287SMartin K. Petersen 	}
2821be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2822c6a44287SMartin K. Petersen 
282365f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
2824c6a44287SMartin K. Petersen 	dix_writes++;
2825c6a44287SMartin K. Petersen 
2826c6a44287SMartin K. Petersen 	return 0;
2827c6a44287SMartin K. Petersen 
2828c6a44287SMartin K. Petersen out:
2829c6a44287SMartin K. Petersen 	dif_errors++;
2830be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
2831be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2832c6a44287SMartin K. Petersen 	return ret;
2833c6a44287SMartin K. Petersen }
2834c6a44287SMartin K. Petersen 
2835b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
2836b90ebc3dSAkinobu Mita {
2837773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2838773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2839773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
2840b90ebc3dSAkinobu Mita 	return lba;
2841b90ebc3dSAkinobu Mita }
2842b90ebc3dSAkinobu Mita 
2843b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
2844b90ebc3dSAkinobu Mita {
2845773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
2846a027b5b9SAkinobu Mita 
2847773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2848773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
2849a027b5b9SAkinobu Mita 	return lba;
2850a027b5b9SAkinobu Mita }
2851a027b5b9SAkinobu Mita 
285244d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
285344d92694SMartin K. Petersen {
2854b90ebc3dSAkinobu Mita 	sector_t end;
2855b90ebc3dSAkinobu Mita 	unsigned int mapped;
2856b90ebc3dSAkinobu Mita 	unsigned long index;
2857b90ebc3dSAkinobu Mita 	unsigned long next;
285844d92694SMartin K. Petersen 
2859b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
2860b90ebc3dSAkinobu Mita 	mapped = test_bit(index, map_storep);
286144d92694SMartin K. Petersen 
286244d92694SMartin K. Petersen 	if (mapped)
2863b90ebc3dSAkinobu Mita 		next = find_next_zero_bit(map_storep, map_size, index);
286444d92694SMartin K. Petersen 	else
2865b90ebc3dSAkinobu Mita 		next = find_next_bit(map_storep, map_size, index);
286644d92694SMartin K. Petersen 
2867b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
286844d92694SMartin K. Petersen 	*num = end - lba;
286944d92694SMartin K. Petersen 	return mapped;
287044d92694SMartin K. Petersen }
287144d92694SMartin K. Petersen 
287244d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
287344d92694SMartin K. Petersen {
287444d92694SMartin K. Petersen 	sector_t end = lba + len;
287544d92694SMartin K. Petersen 
287644d92694SMartin K. Petersen 	while (lba < end) {
2877b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
287844d92694SMartin K. Petersen 
2879b90ebc3dSAkinobu Mita 		if (index < map_size)
2880b90ebc3dSAkinobu Mita 			set_bit(index, map_storep);
288144d92694SMartin K. Petersen 
2882b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
288344d92694SMartin K. Petersen 	}
288444d92694SMartin K. Petersen }
288544d92694SMartin K. Petersen 
288644d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
288744d92694SMartin K. Petersen {
288844d92694SMartin K. Petersen 	sector_t end = lba + len;
288944d92694SMartin K. Petersen 
289044d92694SMartin K. Petersen 	while (lba < end) {
2891b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
289244d92694SMartin K. Petersen 
2893b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
2894773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
2895b90ebc3dSAkinobu Mita 		    index < map_size) {
2896b90ebc3dSAkinobu Mita 			clear_bit(index, map_storep);
2897760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
2898be1dd78dSEric Sandeen 				memset(fake_storep +
2899760f3b03SDouglas Gilbert 				       lba * sdebug_sector_size,
2900760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
2901773642d9SDouglas Gilbert 				       sdebug_sector_size *
2902773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2903be1dd78dSEric Sandeen 			}
2904e9926b43SAkinobu Mita 			if (dif_storep) {
2905e9926b43SAkinobu Mita 				memset(dif_storep + lba, 0xff,
2906e9926b43SAkinobu Mita 				       sizeof(*dif_storep) *
2907773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2908e9926b43SAkinobu Mita 			}
2909b90ebc3dSAkinobu Mita 		}
2910b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
291144d92694SMartin K. Petersen 	}
291244d92694SMartin K. Petersen }
291344d92694SMartin K. Petersen 
2914fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
29151da177e4SLinus Torvalds {
2916c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2917c2248fc9SDouglas Gilbert 	u64 lba;
2918c2248fc9SDouglas Gilbert 	u32 num;
2919c2248fc9SDouglas Gilbert 	u32 ei_lba;
29201da177e4SLinus Torvalds 	unsigned long iflags;
292119789100SFUJITA Tomonori 	int ret;
2922c2248fc9SDouglas Gilbert 	bool check_prot;
29231da177e4SLinus Torvalds 
2924c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2925c2248fc9SDouglas Gilbert 	case WRITE_16:
2926c2248fc9SDouglas Gilbert 		ei_lba = 0;
2927c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2928c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2929c2248fc9SDouglas Gilbert 		check_prot = true;
2930c2248fc9SDouglas Gilbert 		break;
2931c2248fc9SDouglas Gilbert 	case WRITE_10:
2932c2248fc9SDouglas Gilbert 		ei_lba = 0;
2933c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2934c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2935c2248fc9SDouglas Gilbert 		check_prot = true;
2936c2248fc9SDouglas Gilbert 		break;
2937c2248fc9SDouglas Gilbert 	case WRITE_6:
2938c2248fc9SDouglas Gilbert 		ei_lba = 0;
2939c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2940c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2941c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2942c2248fc9SDouglas Gilbert 		check_prot = true;
2943c2248fc9SDouglas Gilbert 		break;
2944c2248fc9SDouglas Gilbert 	case WRITE_12:
2945c2248fc9SDouglas Gilbert 		ei_lba = 0;
2946c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2947c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2948c2248fc9SDouglas Gilbert 		check_prot = true;
2949c2248fc9SDouglas Gilbert 		break;
2950c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
2951c2248fc9SDouglas Gilbert 		ei_lba = 0;
2952c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2953c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2954c2248fc9SDouglas Gilbert 		check_prot = false;
2955c2248fc9SDouglas Gilbert 		break;
2956c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
2957c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2958c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2959c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2960c2248fc9SDouglas Gilbert 		check_prot = false;
2961c2248fc9SDouglas Gilbert 		break;
2962c2248fc9SDouglas Gilbert 	}
2963f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
29648475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2965c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2966c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2967c2248fc9SDouglas Gilbert 			return check_condition_result;
2968c2248fc9SDouglas Gilbert 		}
29698475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
29708475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
2971c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2972c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2973c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2974c2248fc9SDouglas Gilbert 	}
2975c2248fc9SDouglas Gilbert 
2976c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2977f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
2978c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2979c2248fc9SDouglas Gilbert 		return check_condition_result;
2980c2248fc9SDouglas Gilbert 	}
2981c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2982f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
2983c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2984c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2985c2248fc9SDouglas Gilbert 		return check_condition_result;
2986c2248fc9SDouglas Gilbert 	}
29871da177e4SLinus Torvalds 
29886c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
29896c78cc06SAkinobu Mita 
2990c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2991f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
2992c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
2993c6a44287SMartin K. Petersen 
2994c6a44287SMartin K. Petersen 		if (prot_ret) {
29956c78cc06SAkinobu Mita 			write_unlock_irqrestore(&atomic_rw, iflags);
2996c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
2997c6a44287SMartin K. Petersen 			return illegal_condition_result;
2998c6a44287SMartin K. Petersen 		}
2999c6a44287SMartin K. Petersen 	}
3000c6a44287SMartin K. Petersen 
3001c2248fc9SDouglas Gilbert 	ret = do_device_access(scp, lba, num, true);
3002f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
300344d92694SMartin K. Petersen 		map_region(lba, num);
30041da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
3005f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3006773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3007c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3008c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3009c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3010cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3011773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
301244d92694SMartin K. Petersen 
3013f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
3014c4837394SDouglas Gilbert 		struct sdebug_queued_cmd *sqcp =
3015c4837394SDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
3016c2248fc9SDouglas Gilbert 
3017c4837394SDouglas Gilbert 		if (sqcp) {
3018c4837394SDouglas Gilbert 			if (sqcp->inj_recovered) {
3019c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR,
3020c2248fc9SDouglas Gilbert 						THRESHOLD_EXCEEDED, 0);
3021c2248fc9SDouglas Gilbert 				return check_condition_result;
3022c4837394SDouglas Gilbert 			} else if (sqcp->inj_dif) {
3023c2248fc9SDouglas Gilbert 				/* Logical block guard check failed */
3024c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3025c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3026c4837394SDouglas Gilbert 			} else if (sqcp->inj_dix) {
3027c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3028c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3029c2248fc9SDouglas Gilbert 			}
3030c2248fc9SDouglas Gilbert 		}
3031c4837394SDouglas Gilbert 	}
30321da177e4SLinus Torvalds 	return 0;
30331da177e4SLinus Torvalds }
30341da177e4SLinus Torvalds 
3035fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3036fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
303744d92694SMartin K. Petersen {
303844d92694SMartin K. Petersen 	unsigned long iflags;
303944d92694SMartin K. Petersen 	unsigned long long i;
304044d92694SMartin K. Petersen 	int ret;
3041773642d9SDouglas Gilbert 	u64 lba_off;
304244d92694SMartin K. Petersen 
3043c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num);
304444d92694SMartin K. Petersen 	if (ret)
304544d92694SMartin K. Petersen 		return ret;
304644d92694SMartin K. Petersen 
304744d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
304844d92694SMartin K. Petersen 
30499ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
305044d92694SMartin K. Petersen 		unmap_region(lba, num);
305144d92694SMartin K. Petersen 		goto out;
305244d92694SMartin K. Petersen 	}
305344d92694SMartin K. Petersen 
3054773642d9SDouglas Gilbert 	lba_off = lba * sdebug_sector_size;
3055c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
3056c2248fc9SDouglas Gilbert 	if (ndob) {
3057773642d9SDouglas Gilbert 		memset(fake_storep + lba_off, 0, sdebug_sector_size);
3058c2248fc9SDouglas Gilbert 		ret = 0;
3059c2248fc9SDouglas Gilbert 	} else
3060773642d9SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
3061773642d9SDouglas Gilbert 					  sdebug_sector_size);
306244d92694SMartin K. Petersen 
306344d92694SMartin K. Petersen 	if (-1 == ret) {
306444d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
3065773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3066e33d7c56SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < sdebug_sector_size))
3067c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3068e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
3069cbf67842SDouglas Gilbert 			    my_name, "write same",
3070e33d7c56SDouglas Gilbert 			    sdebug_sector_size, ret);
307144d92694SMartin K. Petersen 
307244d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
307344d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
3074773642d9SDouglas Gilbert 		memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
3075773642d9SDouglas Gilbert 		       fake_storep + lba_off,
3076773642d9SDouglas Gilbert 		       sdebug_sector_size);
307744d92694SMartin K. Petersen 
30789ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
307944d92694SMartin K. Petersen 		map_region(lba, num);
308044d92694SMartin K. Petersen out:
308144d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
308244d92694SMartin K. Petersen 
308344d92694SMartin K. Petersen 	return 0;
308444d92694SMartin K. Petersen }
308544d92694SMartin K. Petersen 
3086fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3087fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3088c2248fc9SDouglas Gilbert {
3089c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3090c2248fc9SDouglas Gilbert 	u32 lba;
3091c2248fc9SDouglas Gilbert 	u16 num;
3092c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3093c2248fc9SDouglas Gilbert 	bool unmap = false;
3094c2248fc9SDouglas Gilbert 
3095c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3096773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3097c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3098c2248fc9SDouglas Gilbert 			return check_condition_result;
3099c2248fc9SDouglas Gilbert 		} else
3100c2248fc9SDouglas Gilbert 			unmap = true;
3101c2248fc9SDouglas Gilbert 	}
3102c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3103c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3104773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3105c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3106c2248fc9SDouglas Gilbert 		return check_condition_result;
3107c2248fc9SDouglas Gilbert 	}
3108c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3109c2248fc9SDouglas Gilbert }
3110c2248fc9SDouglas Gilbert 
3111fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3112fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3113c2248fc9SDouglas Gilbert {
3114c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3115c2248fc9SDouglas Gilbert 	u64 lba;
3116c2248fc9SDouglas Gilbert 	u32 num;
3117c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3118c2248fc9SDouglas Gilbert 	bool unmap = false;
3119c2248fc9SDouglas Gilbert 	bool ndob = false;
3120c2248fc9SDouglas Gilbert 
3121c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3122773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3123c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3124c2248fc9SDouglas Gilbert 			return check_condition_result;
3125c2248fc9SDouglas Gilbert 		} else
3126c2248fc9SDouglas Gilbert 			unmap = true;
3127c2248fc9SDouglas Gilbert 	}
3128c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3129c2248fc9SDouglas Gilbert 		ndob = true;
3130c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3131c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3132773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3133c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3134c2248fc9SDouglas Gilbert 		return check_condition_result;
3135c2248fc9SDouglas Gilbert 	}
3136c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3137c2248fc9SDouglas Gilbert }
3138c2248fc9SDouglas Gilbert 
3139acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3140acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3141acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3142fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3143fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3144acafd0b9SEwan D. Milne {
3145acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3146acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3147acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3148acafd0b9SEwan D. Milne 	u8 mode;
3149acafd0b9SEwan D. Milne 
3150acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3151acafd0b9SEwan D. Milne 	switch (mode) {
3152acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3153acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3154acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3155acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3156acafd0b9SEwan D. Milne 		break;
3157acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3158acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3159acafd0b9SEwan D. Milne 		break;
3160acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3161acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3162acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3163acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3164acafd0b9SEwan D. Milne 				    dev_list)
3165acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3166acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3167acafd0b9SEwan D. Milne 				if (devip != dp)
3168acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3169acafd0b9SEwan D. Milne 						dp->uas_bm);
3170acafd0b9SEwan D. Milne 			}
3171acafd0b9SEwan D. Milne 		break;
3172acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3173acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3174acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3175acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3176acafd0b9SEwan D. Milne 				    dev_list)
3177acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3178acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3179acafd0b9SEwan D. Milne 					dp->uas_bm);
3180acafd0b9SEwan D. Milne 		break;
3181acafd0b9SEwan D. Milne 	default:
3182acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3183acafd0b9SEwan D. Milne 		break;
3184acafd0b9SEwan D. Milne 	}
3185acafd0b9SEwan D. Milne 	return 0;
3186acafd0b9SEwan D. Milne }
3187acafd0b9SEwan D. Milne 
3188fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3189fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
319038d5c833SDouglas Gilbert {
319138d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
319238d5c833SDouglas Gilbert 	u8 *arr;
319338d5c833SDouglas Gilbert 	u8 *fake_storep_hold;
319438d5c833SDouglas Gilbert 	u64 lba;
319538d5c833SDouglas Gilbert 	u32 dnum;
3196773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
319738d5c833SDouglas Gilbert 	u8 num;
319838d5c833SDouglas Gilbert 	unsigned long iflags;
319938d5c833SDouglas Gilbert 	int ret;
3200d467d31fSDouglas Gilbert 	int retval = 0;
320138d5c833SDouglas Gilbert 
3202d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
320338d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
320438d5c833SDouglas Gilbert 	if (0 == num)
320538d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
32068475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
320738d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
320838d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
320938d5c833SDouglas Gilbert 		return check_condition_result;
321038d5c833SDouglas Gilbert 	}
32118475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
32128475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
321338d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
321438d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
321538d5c833SDouglas Gilbert 			    "to DIF device\n");
321638d5c833SDouglas Gilbert 
321738d5c833SDouglas Gilbert 	/* inline check_device_access_params() */
321838d5c833SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
321938d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
322038d5c833SDouglas Gilbert 		return check_condition_result;
322138d5c833SDouglas Gilbert 	}
322238d5c833SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
322338d5c833SDouglas Gilbert 	if (num > sdebug_store_sectors) {
322438d5c833SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
322538d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
322638d5c833SDouglas Gilbert 		return check_condition_result;
322738d5c833SDouglas Gilbert 	}
3228d467d31fSDouglas Gilbert 	dnum = 2 * num;
3229d467d31fSDouglas Gilbert 	arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3230d467d31fSDouglas Gilbert 	if (NULL == arr) {
3231d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3232d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3233d467d31fSDouglas Gilbert 		return check_condition_result;
3234d467d31fSDouglas Gilbert 	}
323538d5c833SDouglas Gilbert 
323638d5c833SDouglas Gilbert 	write_lock_irqsave(&atomic_rw, iflags);
323738d5c833SDouglas Gilbert 
323838d5c833SDouglas Gilbert 	/* trick do_device_access() to fetch both compare and write buffers
323938d5c833SDouglas Gilbert 	 * from data-in into arr. Safe (atomic) since write_lock held. */
324038d5c833SDouglas Gilbert 	fake_storep_hold = fake_storep;
324138d5c833SDouglas Gilbert 	fake_storep = arr;
324238d5c833SDouglas Gilbert 	ret = do_device_access(scp, 0, dnum, true);
324338d5c833SDouglas Gilbert 	fake_storep = fake_storep_hold;
324438d5c833SDouglas Gilbert 	if (ret == -1) {
3245d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3246d467d31fSDouglas Gilbert 		goto cleanup;
3247773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
324838d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
324938d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
325038d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
325138d5c833SDouglas Gilbert 	if (!comp_write_worker(lba, num, arr)) {
325238d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3253d467d31fSDouglas Gilbert 		retval = check_condition_result;
3254d467d31fSDouglas Gilbert 		goto cleanup;
325538d5c833SDouglas Gilbert 	}
325638d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
325738d5c833SDouglas Gilbert 		map_region(lba, num);
3258d467d31fSDouglas Gilbert cleanup:
325938d5c833SDouglas Gilbert 	write_unlock_irqrestore(&atomic_rw, iflags);
3260d467d31fSDouglas Gilbert 	kfree(arr);
3261d467d31fSDouglas Gilbert 	return retval;
326238d5c833SDouglas Gilbert }
326338d5c833SDouglas Gilbert 
326444d92694SMartin K. Petersen struct unmap_block_desc {
326544d92694SMartin K. Petersen 	__be64	lba;
326644d92694SMartin K. Petersen 	__be32	blocks;
326744d92694SMartin K. Petersen 	__be32	__reserved;
326844d92694SMartin K. Petersen };
326944d92694SMartin K. Petersen 
3270fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
327144d92694SMartin K. Petersen {
327244d92694SMartin K. Petersen 	unsigned char *buf;
327344d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
327444d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
327544d92694SMartin K. Petersen 	int ret;
32766c78cc06SAkinobu Mita 	unsigned long iflags;
327744d92694SMartin K. Petersen 
327844d92694SMartin K. Petersen 
3279c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3280c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3281c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3282c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
328344d92694SMartin K. Petersen 
328444d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3285773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3286c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
328744d92694SMartin K. Petersen 		return check_condition_result;
3288c2248fc9SDouglas Gilbert 	}
328944d92694SMartin K. Petersen 
3290b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3291c2248fc9SDouglas Gilbert 	if (!buf) {
3292c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3293c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3294c2248fc9SDouglas Gilbert 		return check_condition_result;
3295c2248fc9SDouglas Gilbert 	}
3296c2248fc9SDouglas Gilbert 
3297c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
329844d92694SMartin K. Petersen 
329944d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
330044d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
330144d92694SMartin K. Petersen 
330244d92694SMartin K. Petersen 	desc = (void *)&buf[8];
330344d92694SMartin K. Petersen 
33046c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
33056c78cc06SAkinobu Mita 
330644d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
330744d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
330844d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
330944d92694SMartin K. Petersen 
3310c2248fc9SDouglas Gilbert 		ret = check_device_access_params(scp, lba, num);
331144d92694SMartin K. Petersen 		if (ret)
331244d92694SMartin K. Petersen 			goto out;
331344d92694SMartin K. Petersen 
331444d92694SMartin K. Petersen 		unmap_region(lba, num);
331544d92694SMartin K. Petersen 	}
331644d92694SMartin K. Petersen 
331744d92694SMartin K. Petersen 	ret = 0;
331844d92694SMartin K. Petersen 
331944d92694SMartin K. Petersen out:
33206c78cc06SAkinobu Mita 	write_unlock_irqrestore(&atomic_rw, iflags);
332144d92694SMartin K. Petersen 	kfree(buf);
332244d92694SMartin K. Petersen 
332344d92694SMartin K. Petersen 	return ret;
332444d92694SMartin K. Petersen }
332544d92694SMartin K. Petersen 
332644d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
332744d92694SMartin K. Petersen 
3328fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
3329fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
333044d92694SMartin K. Petersen {
3331c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3332c2248fc9SDouglas Gilbert 	u64 lba;
3333c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
3334c2248fc9SDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
333544d92694SMartin K. Petersen 	int ret;
333644d92694SMartin K. Petersen 
3337c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3338c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
333944d92694SMartin K. Petersen 
334044d92694SMartin K. Petersen 	if (alloc_len < 24)
334144d92694SMartin K. Petersen 		return 0;
334244d92694SMartin K. Petersen 
3343c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, 1);
334444d92694SMartin K. Petersen 	if (ret)
334544d92694SMartin K. Petersen 		return ret;
334644d92694SMartin K. Petersen 
3347c2248fc9SDouglas Gilbert 	if (scsi_debug_lbp())
334844d92694SMartin K. Petersen 		mapped = map_state(lba, &num);
3349c2248fc9SDouglas Gilbert 	else {
3350c2248fc9SDouglas Gilbert 		mapped = 1;
3351c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
3352c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
3353c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
3354c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
3355c2248fc9SDouglas Gilbert 		else
3356c2248fc9SDouglas Gilbert 			num = 0xffffffff;
3357c2248fc9SDouglas Gilbert 	}
335844d92694SMartin K. Petersen 
335944d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
3360c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
3361c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
3362c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
3363c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
336444d92694SMartin K. Petersen 
3365c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
336644d92694SMartin K. Petersen }
336744d92694SMartin K. Petersen 
3368fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
3369fb0cc8d1SDouglas Gilbert 
33708d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
33718d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
33728d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
33738d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
33748d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
33758d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
33768d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
33778d039e22SDouglas Gilbert  */
33781da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
33791da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
33801da177e4SLinus Torvalds {
338101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
33828d039e22SDouglas Gilbert 	unsigned int alloc_len;
33838d039e22SDouglas Gilbert 	unsigned char select_report;
33848d039e22SDouglas Gilbert 	u64 lun;
33858d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
3386fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
33878d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
33888d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
33898d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
33908d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
3391fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
3392fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
3393fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
33941da177e4SLinus Torvalds 
339519c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
33968d039e22SDouglas Gilbert 
33978d039e22SDouglas Gilbert 	select_report = cmd[2];
33988d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
33998d039e22SDouglas Gilbert 
34008d039e22SDouglas Gilbert 	if (alloc_len < 4) {
34018d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
34028d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
34031da177e4SLinus Torvalds 		return check_condition_result;
34041da177e4SLinus Torvalds 	}
34058d039e22SDouglas Gilbert 
34068d039e22SDouglas Gilbert 	switch (select_report) {
34078d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
3408773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
34098d039e22SDouglas Gilbert 		wlun_cnt = 0;
34108d039e22SDouglas Gilbert 		break;
34118d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
3412c65b1445SDouglas Gilbert 		lun_cnt = 0;
34138d039e22SDouglas Gilbert 		wlun_cnt = 1;
34148d039e22SDouglas Gilbert 		break;
34158d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
34168d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
34178d039e22SDouglas Gilbert 		wlun_cnt = 1;
34188d039e22SDouglas Gilbert 		break;
34198d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
34208d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
34218d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
34228d039e22SDouglas Gilbert 	default:
34238d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
34248d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
34258d039e22SDouglas Gilbert 		return check_condition_result;
34268d039e22SDouglas Gilbert 	}
34278d039e22SDouglas Gilbert 
34288d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
3429c65b1445SDouglas Gilbert 		--lun_cnt;
34308d039e22SDouglas Gilbert 
34318d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
3432fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
3433fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
34348d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
34358d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
34368d039e22SDouglas Gilbert 
3437fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
34388d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
3439fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3440fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
3441fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
3442fb0cc8d1SDouglas Gilbert 		if (k == 0) {
3443fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
3444fb0cc8d1SDouglas Gilbert 			++lun_p;
3445fb0cc8d1SDouglas Gilbert 			j = 1;
3446fb0cc8d1SDouglas Gilbert 		}
3447fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3448fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3449fb0cc8d1SDouglas Gilbert 				break;
3450fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
3451fb0cc8d1SDouglas Gilbert 		}
3452fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
3453fb0cc8d1SDouglas Gilbert 			break;
3454fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
3455fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3456fb0cc8d1SDouglas Gilbert 		if (res)
3457fb0cc8d1SDouglas Gilbert 			return res;
3458fb0cc8d1SDouglas Gilbert 		off_rsp += n;
3459fb0cc8d1SDouglas Gilbert 	}
3460fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
3461fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3462fb0cc8d1SDouglas Gilbert 		++j;
3463fb0cc8d1SDouglas Gilbert 	}
3464fb0cc8d1SDouglas Gilbert 	if (j > 0)
3465fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
34668d039e22SDouglas Gilbert 	return res;
34671da177e4SLinus Torvalds }
34681da177e4SLinus Torvalds 
3469c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3470c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
3471c639d14eSFUJITA Tomonori {
3472be4e11beSAkinobu Mita 	int j;
3473c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
3474c639d14eSFUJITA Tomonori 	unsigned int offset;
3475c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
3476be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3477c639d14eSFUJITA Tomonori 
3478c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
3479b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3480c5af0db9SAkinobu Mita 	if (!buf) {
348122017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
348222017ed2SDouglas Gilbert 				INSUFF_RES_ASCQ);
3483c5af0db9SAkinobu Mita 		return check_condition_result;
3484c5af0db9SAkinobu Mita 	}
3485c639d14eSFUJITA Tomonori 
348621a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
3487c639d14eSFUJITA Tomonori 
3488c639d14eSFUJITA Tomonori 	offset = 0;
3489be4e11beSAkinobu Mita 	sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3490be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_TO_SG);
3491c639d14eSFUJITA Tomonori 
3492be4e11beSAkinobu Mita 	while (sg_miter_next(&miter)) {
3493be4e11beSAkinobu Mita 		kaddr = miter.addr;
3494be4e11beSAkinobu Mita 		for (j = 0; j < miter.length; j++)
3495be4e11beSAkinobu Mita 			*(kaddr + j) ^= *(buf + offset + j);
3496c639d14eSFUJITA Tomonori 
3497be4e11beSAkinobu Mita 		offset += miter.length;
3498c639d14eSFUJITA Tomonori 	}
3499be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3500c639d14eSFUJITA Tomonori 	kfree(buf);
3501c639d14eSFUJITA Tomonori 
3502be4e11beSAkinobu Mita 	return 0;
3503c639d14eSFUJITA Tomonori }
3504c639d14eSFUJITA Tomonori 
3505fd32119bSDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3506fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
3507c2248fc9SDouglas Gilbert {
3508c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3509c2248fc9SDouglas Gilbert 	u64 lba;
3510c2248fc9SDouglas Gilbert 	u32 num;
3511c2248fc9SDouglas Gilbert 	int errsts;
3512c2248fc9SDouglas Gilbert 
3513c2248fc9SDouglas Gilbert 	if (!scsi_bidi_cmnd(scp)) {
3514c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3515c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3516c2248fc9SDouglas Gilbert 		return check_condition_result;
3517c2248fc9SDouglas Gilbert 	}
3518c2248fc9SDouglas Gilbert 	errsts = resp_read_dt0(scp, devip);
3519c2248fc9SDouglas Gilbert 	if (errsts)
3520c2248fc9SDouglas Gilbert 		return errsts;
3521c2248fc9SDouglas Gilbert 	if (!(cmd[1] & 0x4)) {		/* DISABLE_WRITE is not set */
3522c2248fc9SDouglas Gilbert 		errsts = resp_write_dt0(scp, devip);
3523c2248fc9SDouglas Gilbert 		if (errsts)
3524c2248fc9SDouglas Gilbert 			return errsts;
3525c2248fc9SDouglas Gilbert 	}
3526c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3527c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3528c2248fc9SDouglas Gilbert 	return resp_xdwriteread(scp, lba, num, devip);
3529c2248fc9SDouglas Gilbert }
3530c2248fc9SDouglas Gilbert 
3531c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3532c4837394SDouglas Gilbert {
3533c4837394SDouglas Gilbert 	struct sdebug_queue *sqp = sdebug_q_arr;
3534c4837394SDouglas Gilbert 
3535c4837394SDouglas Gilbert 	if (sdebug_mq_active) {
3536c4837394SDouglas Gilbert 		u32 tag = blk_mq_unique_tag(cmnd->request);
3537c4837394SDouglas Gilbert 		u16 hwq = blk_mq_unique_tag_to_hwq(tag);
3538c4837394SDouglas Gilbert 
3539c4837394SDouglas Gilbert 		if (unlikely(hwq >= submit_queues)) {
3540c4837394SDouglas Gilbert 			pr_warn("Unexpected hwq=%d, apply modulo\n", hwq);
3541c4837394SDouglas Gilbert 			hwq %= submit_queues;
3542c4837394SDouglas Gilbert 		}
3543c4837394SDouglas Gilbert 		pr_debug("tag=%u, hwq=%d\n", tag, hwq);
3544c4837394SDouglas Gilbert 		return sqp + hwq;
3545c4837394SDouglas Gilbert 	} else
3546c4837394SDouglas Gilbert 		return sqp;
3547c4837394SDouglas Gilbert }
3548c4837394SDouglas Gilbert 
3549c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
3550fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
35511da177e4SLinus Torvalds {
3552c4837394SDouglas Gilbert 	int qc_idx;
3553cbf67842SDouglas Gilbert 	int retiring = 0;
35541da177e4SLinus Torvalds 	unsigned long iflags;
3555c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3556cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3557cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
3558cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
35591da177e4SLinus Torvalds 
3560c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
3561c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
3562c4837394SDouglas Gilbert 	if (sdebug_statistics) {
3563cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
3564c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3565c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
3566c4837394SDouglas Gilbert 	}
3567c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3568c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
35691da177e4SLinus Torvalds 		return;
35701da177e4SLinus Torvalds 	}
3571c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
3572c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
3573cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
3574b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
3575c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3576c4837394SDouglas Gilbert 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3577c4837394SDouglas Gilbert 		       sd_dp->sqa_idx, qc_idx);
35781da177e4SLinus Torvalds 		return;
35791da177e4SLinus Torvalds 	}
3580cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
3581f46eb0e9SDouglas Gilbert 	if (likely(devip))
3582cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
3583cbf67842SDouglas Gilbert 	else
3584c1287970STomas Winkler 		pr_err("devip=NULL\n");
3585f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
3586cbf67842SDouglas Gilbert 		retiring = 1;
3587cbf67842SDouglas Gilbert 
3588cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
3589c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3590c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3591c1287970STomas Winkler 		pr_err("Unexpected completion\n");
3592cbf67842SDouglas Gilbert 		return;
35931da177e4SLinus Torvalds 	}
35941da177e4SLinus Torvalds 
3595cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
3596cbf67842SDouglas Gilbert 		int k, retval;
3597cbf67842SDouglas Gilbert 
3598cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
3599c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
3600c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3601c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
3602cbf67842SDouglas Gilbert 			return;
3603cbf67842SDouglas Gilbert 		}
3604c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
3605773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
3606cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3607cbf67842SDouglas Gilbert 		else
3608cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
3609cbf67842SDouglas Gilbert 	}
3610c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3611cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
3612cbf67842SDouglas Gilbert }
3613cbf67842SDouglas Gilbert 
3614cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
3615fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
3616cbf67842SDouglas Gilbert {
3617a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3618a10bc12aSDouglas Gilbert 						  hrt);
3619a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3620cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
3621cbf67842SDouglas Gilbert }
36221da177e4SLinus Torvalds 
3623a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
3624fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
3625a10bc12aSDouglas Gilbert {
3626a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3627a10bc12aSDouglas Gilbert 						  ew.work);
3628a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3629a10bc12aSDouglas Gilbert }
3630a10bc12aSDouglas Gilbert 
363109ba24c1SDouglas Gilbert static bool got_shared_uuid;
3632bf476433SChristoph Hellwig static uuid_t shared_uuid;
363309ba24c1SDouglas Gilbert 
3634fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
3635fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
36365cb2fc06SFUJITA Tomonori {
36375cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
36385cb2fc06SFUJITA Tomonori 
36395cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
36405cb2fc06SFUJITA Tomonori 	if (devip) {
364109ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
3642bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
364309ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
364409ba24c1SDouglas Gilbert 			if (got_shared_uuid)
364509ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
364609ba24c1SDouglas Gilbert 			else {
3647bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
364809ba24c1SDouglas Gilbert 				got_shared_uuid = true;
364909ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
365009ba24c1SDouglas Gilbert 			}
365109ba24c1SDouglas Gilbert 		}
36525cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
36535cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
36545cb2fc06SFUJITA Tomonori 	}
36555cb2fc06SFUJITA Tomonori 	return devip;
36565cb2fc06SFUJITA Tomonori }
36575cb2fc06SFUJITA Tomonori 
3658f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
36591da177e4SLinus Torvalds {
36601da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
36611da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
3662f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
36631da177e4SLinus Torvalds 
3664d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
36651da177e4SLinus Torvalds 	if (!sdbg_host) {
3666c1287970STomas Winkler 		pr_err("Host info NULL\n");
36671da177e4SLinus Torvalds 		return NULL;
36681da177e4SLinus Torvalds         }
36691da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
36701da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
36711da177e4SLinus Torvalds                     (devip->target == sdev->id) &&
36721da177e4SLinus Torvalds                     (devip->lun == sdev->lun))
36731da177e4SLinus Torvalds                         return devip;
36741da177e4SLinus Torvalds 		else {
36751da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
36761da177e4SLinus Torvalds 				open_devip = devip;
36771da177e4SLinus Torvalds 		}
36781da177e4SLinus Torvalds 	}
36795cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
36805cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
36815cb2fc06SFUJITA Tomonori 		if (!open_devip) {
3682c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
36831da177e4SLinus Torvalds 			return NULL;
36841da177e4SLinus Torvalds 		}
36851da177e4SLinus Torvalds 	}
3686a75869d1SFUJITA Tomonori 
36871da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
36881da177e4SLinus Torvalds 	open_devip->target = sdev->id;
36891da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
36901da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
3691cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
3692cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
3693c2248fc9SDouglas Gilbert 	open_devip->used = true;
36941da177e4SLinus Torvalds 	return open_devip;
36951da177e4SLinus Torvalds }
36961da177e4SLinus Torvalds 
36978dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
36981da177e4SLinus Torvalds {
3699773642d9SDouglas Gilbert 	if (sdebug_verbose)
3700c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
37018dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
370275ad23bcSNick Piggin 	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
37038dea0d02SFUJITA Tomonori 	return 0;
37048dea0d02SFUJITA Tomonori }
37051da177e4SLinus Torvalds 
37068dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
37078dea0d02SFUJITA Tomonori {
3708f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
3709f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
3710a34c4e98SFUJITA Tomonori 
3711773642d9SDouglas Gilbert 	if (sdebug_verbose)
3712c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
37138dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3714b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3715b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3716b01f6f83SDouglas Gilbert 	if (devip == NULL) {
3717f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
3718b01f6f83SDouglas Gilbert 		if (devip == NULL)
37198dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
3720f46eb0e9SDouglas Gilbert 	}
3721c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
37226bb5e6e7SAkinobu Mita 	blk_queue_max_segment_size(sdp->request_queue, -1U);
3723773642d9SDouglas Gilbert 	if (sdebug_no_uld)
372478d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
37259b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
37268dea0d02SFUJITA Tomonori 	return 0;
37278dea0d02SFUJITA Tomonori }
37288dea0d02SFUJITA Tomonori 
37298dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
37308dea0d02SFUJITA Tomonori {
37318dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
37328dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
37338dea0d02SFUJITA Tomonori 
3734773642d9SDouglas Gilbert 	if (sdebug_verbose)
3735c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
37368dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
37378dea0d02SFUJITA Tomonori 	if (devip) {
373825985edcSLucas De Marchi 		/* make this slot available for re-use */
3739c2248fc9SDouglas Gilbert 		devip->used = false;
37408dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
37418dea0d02SFUJITA Tomonori 	}
37428dea0d02SFUJITA Tomonori }
37438dea0d02SFUJITA Tomonori 
3744c4837394SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp)
3745c4837394SDouglas Gilbert {
3746c4837394SDouglas Gilbert 	if (!sd_dp)
3747c4837394SDouglas Gilbert 		return;
3748c4837394SDouglas Gilbert 	if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0))
3749c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
3750c4837394SDouglas Gilbert 	else if (sdebug_jdelay < 0)
3751c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
3752c4837394SDouglas Gilbert }
3753c4837394SDouglas Gilbert 
3754a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
3755a10bc12aSDouglas Gilbert    returns false */
3756a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
37578dea0d02SFUJITA Tomonori {
37588dea0d02SFUJITA Tomonori 	unsigned long iflags;
3759c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
3760c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
37618dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3762cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3763a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
37648dea0d02SFUJITA Tomonori 
3765c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3766c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
3767773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
3768cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
3769cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
3770cbf67842SDouglas Gilbert 			qmax = r_qmax;
3771cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
3772c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
3773c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
3774a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
3775a10bc12aSDouglas Gilbert 					continue;
3776c4837394SDouglas Gilbert 				/* found */
3777db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3778db525fceSDouglas Gilbert 						cmnd->device->hostdata;
3779db525fceSDouglas Gilbert 				if (devip)
3780db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3781db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3782a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
3783c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3784c4837394SDouglas Gilbert 				stop_qc_helper(sd_dp);
3785c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
3786a10bc12aSDouglas Gilbert 				return true;
37878dea0d02SFUJITA Tomonori 			}
3788cbf67842SDouglas Gilbert 		}
3789c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3790c4837394SDouglas Gilbert 	}
3791a10bc12aSDouglas Gilbert 	return false;
37928dea0d02SFUJITA Tomonori }
37938dea0d02SFUJITA Tomonori 
3794a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
37958dea0d02SFUJITA Tomonori static void stop_all_queued(void)
37968dea0d02SFUJITA Tomonori {
37978dea0d02SFUJITA Tomonori 	unsigned long iflags;
3798c4837394SDouglas Gilbert 	int j, k;
3799c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
38008dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3801cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3802a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
38038dea0d02SFUJITA Tomonori 
3804c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3805c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
3806c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3807c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
3808c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
3809c4837394SDouglas Gilbert 				if (sqcp->a_cmnd == NULL)
3810a10bc12aSDouglas Gilbert 					continue;
3811db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3812db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
3813db525fceSDouglas Gilbert 				if (devip)
3814db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3815db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3816a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
3817c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3818c4837394SDouglas Gilbert 				stop_qc_helper(sd_dp);
3819c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
3820c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
38218dea0d02SFUJITA Tomonori 			}
38228dea0d02SFUJITA Tomonori 		}
3823c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3824c4837394SDouglas Gilbert 	}
3825cbf67842SDouglas Gilbert }
3826cbf67842SDouglas Gilbert 
3827cbf67842SDouglas Gilbert /* Free queued command memory on heap */
3828cbf67842SDouglas Gilbert static void free_all_queued(void)
3829cbf67842SDouglas Gilbert {
3830c4837394SDouglas Gilbert 	int j, k;
3831c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3832cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3833cbf67842SDouglas Gilbert 
3834c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3835c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3836c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
3837a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
3838a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
3839cbf67842SDouglas Gilbert 		}
38401da177e4SLinus Torvalds 	}
3841c4837394SDouglas Gilbert }
38421da177e4SLinus Torvalds 
38431da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
38441da177e4SLinus Torvalds {
3845a10bc12aSDouglas Gilbert 	bool ok;
3846a10bc12aSDouglas Gilbert 
38471da177e4SLinus Torvalds 	++num_aborts;
3848cbf67842SDouglas Gilbert 	if (SCpnt) {
3849a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
3850a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3851a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
3852a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
3853a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
3854cbf67842SDouglas Gilbert 	}
38551da177e4SLinus Torvalds 	return SUCCESS;
38561da177e4SLinus Torvalds }
38571da177e4SLinus Torvalds 
38581da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
38591da177e4SLinus Torvalds {
38601da177e4SLinus Torvalds 	++num_dev_resets;
3861cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
3862cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
3863f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
3864f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
3865cbf67842SDouglas Gilbert 
3866773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3867cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
38681da177e4SLinus Torvalds 		if (devip)
3869cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
38701da177e4SLinus Torvalds 	}
38711da177e4SLinus Torvalds 	return SUCCESS;
38721da177e4SLinus Torvalds }
38731da177e4SLinus Torvalds 
3874cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3875cbf67842SDouglas Gilbert {
3876cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
3877cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3878cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
3879cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
3880cbf67842SDouglas Gilbert 	int k = 0;
3881cbf67842SDouglas Gilbert 
3882cbf67842SDouglas Gilbert 	++num_target_resets;
3883cbf67842SDouglas Gilbert 	if (!SCpnt)
3884cbf67842SDouglas Gilbert 		goto lie;
3885cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
3886cbf67842SDouglas Gilbert 	if (!sdp)
3887cbf67842SDouglas Gilbert 		goto lie;
3888773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3889cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3890cbf67842SDouglas Gilbert 	hp = sdp->host;
3891cbf67842SDouglas Gilbert 	if (!hp)
3892cbf67842SDouglas Gilbert 		goto lie;
3893cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3894cbf67842SDouglas Gilbert 	if (sdbg_host) {
3895cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
3896cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
3897cbf67842SDouglas Gilbert 				    dev_list)
3898cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
3899cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3900cbf67842SDouglas Gilbert 				++k;
3901cbf67842SDouglas Gilbert 			}
3902cbf67842SDouglas Gilbert 	}
3903773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3904cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3905cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
3906cbf67842SDouglas Gilbert lie:
3907cbf67842SDouglas Gilbert 	return SUCCESS;
3908cbf67842SDouglas Gilbert }
3909cbf67842SDouglas Gilbert 
39101da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
39111da177e4SLinus Torvalds {
39121da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
3913cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
39141da177e4SLinus Torvalds         struct scsi_device * sdp;
39151da177e4SLinus Torvalds         struct Scsi_Host * hp;
3916cbf67842SDouglas Gilbert 	int k = 0;
39171da177e4SLinus Torvalds 
39181da177e4SLinus Torvalds 	++num_bus_resets;
3919cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
3920cbf67842SDouglas Gilbert 		goto lie;
3921cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
3922773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3923cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3924cbf67842SDouglas Gilbert 	hp = sdp->host;
3925cbf67842SDouglas Gilbert 	if (hp) {
3926d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
39271da177e4SLinus Torvalds 		if (sdbg_host) {
3928cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
39291da177e4SLinus Torvalds                                             &sdbg_host->dev_info_list,
3930cbf67842SDouglas Gilbert 					    dev_list) {
3931cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3932cbf67842SDouglas Gilbert 				++k;
39331da177e4SLinus Torvalds 			}
39341da177e4SLinus Torvalds 		}
3935cbf67842SDouglas Gilbert 	}
3936773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3937cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3938cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
3939cbf67842SDouglas Gilbert lie:
39401da177e4SLinus Torvalds 	return SUCCESS;
39411da177e4SLinus Torvalds }
39421da177e4SLinus Torvalds 
39431da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
39441da177e4SLinus Torvalds {
39451da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
3946cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3947cbf67842SDouglas Gilbert 	int k = 0;
39481da177e4SLinus Torvalds 
39491da177e4SLinus Torvalds 	++num_host_resets;
3950773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3951cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
39521da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
39531da177e4SLinus Torvalds         list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3954cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
3955cbf67842SDouglas Gilbert 				    dev_list) {
3956cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3957cbf67842SDouglas Gilbert 			++k;
3958cbf67842SDouglas Gilbert 		}
39591da177e4SLinus Torvalds         }
39601da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
39611da177e4SLinus Torvalds 	stop_all_queued();
3962773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3963cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
3964cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
39651da177e4SLinus Torvalds 	return SUCCESS;
39661da177e4SLinus Torvalds }
39671da177e4SLinus Torvalds 
3968f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
39695f2578e5SFUJITA Tomonori 				      unsigned long store_size)
39701da177e4SLinus Torvalds {
39711da177e4SLinus Torvalds 	struct partition * pp;
39721da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
39731da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
39741da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
39751da177e4SLinus Torvalds 
39761da177e4SLinus Torvalds 	/* assume partition table already zeroed */
3977773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
39781da177e4SLinus Torvalds 		return;
3979773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
3980773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
3981c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
39821da177e4SLinus Torvalds 	}
3983c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
39841da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
3985773642d9SDouglas Gilbert 			   / sdebug_num_parts;
39861da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
39871da177e4SLinus Torvalds         starts[0] = sdebug_sectors_per;
3988773642d9SDouglas Gilbert 	for (k = 1; k < sdebug_num_parts; ++k)
39891da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
39901da177e4SLinus Torvalds 			    * heads_by_sects;
3991773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
3992773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
39931da177e4SLinus Torvalds 
39941da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
39951da177e4SLinus Torvalds 	ramp[511] = 0xAA;
39961da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
39971da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
39981da177e4SLinus Torvalds 		start_sec = starts[k];
39991da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
40001da177e4SLinus Torvalds 		pp->boot_ind = 0;
40011da177e4SLinus Torvalds 
40021da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
40031da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
40041da177e4SLinus Torvalds 			   / sdebug_sectors_per;
40051da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
40061da177e4SLinus Torvalds 
40071da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
40081da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
40091da177e4SLinus Torvalds 			       / sdebug_sectors_per;
40101da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
40111da177e4SLinus Torvalds 
4012150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
4013150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
40141da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
40151da177e4SLinus Torvalds 	}
40161da177e4SLinus Torvalds }
40171da177e4SLinus Torvalds 
4018c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block)
4019c4837394SDouglas Gilbert {
4020c4837394SDouglas Gilbert 	int j;
4021c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4022c4837394SDouglas Gilbert 
4023c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
4024c4837394SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)block);
4025c4837394SDouglas Gilbert }
4026c4837394SDouglas Gilbert 
4027c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
4028c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
4029c4837394SDouglas Gilbert  */
4030c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
4031c4837394SDouglas Gilbert {
4032c4837394SDouglas Gilbert 	int count, modulo;
4033c4837394SDouglas Gilbert 
4034c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
4035c4837394SDouglas Gilbert 	if (modulo < 2)
4036c4837394SDouglas Gilbert 		return;
4037c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
4038c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
4039c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
4040c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
4041c4837394SDouglas Gilbert }
4042c4837394SDouglas Gilbert 
4043c4837394SDouglas Gilbert static void clear_queue_stats(void)
4044c4837394SDouglas Gilbert {
4045c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
4046c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
4047c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
4048c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
4049c4837394SDouglas Gilbert }
4050c4837394SDouglas Gilbert 
4051c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp,
4052c4837394SDouglas Gilbert 			 struct sdebug_queued_cmd *sqcp)
4053c4837394SDouglas Gilbert {
4054c4837394SDouglas Gilbert 	if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0)
4055c4837394SDouglas Gilbert 		return;
4056c4837394SDouglas Gilbert 	sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
4057c4837394SDouglas Gilbert 	sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
4058c4837394SDouglas Gilbert 	sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
4059c4837394SDouglas Gilbert 	sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
4060c4837394SDouglas Gilbert 	sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
40617ee6d1b4SBart Van Assche 	sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
4062c4837394SDouglas Gilbert }
4063c4837394SDouglas Gilbert 
4064c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
4065c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
4066c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
4067c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
4068c4837394SDouglas Gilbert  */
4069fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
4070cbf67842SDouglas Gilbert 			 int scsi_result, int delta_jiff)
40711da177e4SLinus Torvalds {
4072cbf67842SDouglas Gilbert 	unsigned long iflags;
4073cd62b7daSDouglas Gilbert 	int k, num_in_q, qdepth, inject;
4074c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4075c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4076299b6c07STomas Winkler 	struct scsi_device *sdp;
4077a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
40781da177e4SLinus Torvalds 
4079b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
4080b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
4081f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
4082f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
40831da177e4SLinus Torvalds 	}
4084299b6c07STomas Winkler 	sdp = cmnd->device;
4085299b6c07STomas Winkler 
4086f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose && scsi_result))
4087cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4088cbf67842SDouglas Gilbert 			    __func__, scsi_result);
4089cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
4090cd62b7daSDouglas Gilbert 		goto respond_in_thread;
40911da177e4SLinus Torvalds 
4092cd62b7daSDouglas Gilbert 	/* schedule the response at a later time if resources permit */
4093c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
4094c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
4095c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
4096c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4097c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
4098c4837394SDouglas Gilbert 	}
4099cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
4100cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
4101cbf67842SDouglas Gilbert 	inject = 0;
4102f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
4103cd62b7daSDouglas Gilbert 		if (scsi_result) {
4104c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4105cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4106cd62b7daSDouglas Gilbert 		} else
4107cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4108c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
4109773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4110f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
4111cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
4112cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
4113773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
4114cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
4115cbf67842SDouglas Gilbert 			inject = 1;
4116cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
41171da177e4SLinus Torvalds 		}
4118cbf67842SDouglas Gilbert 	}
4119cbf67842SDouglas Gilbert 
4120c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
4121f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
4122c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4123cd62b7daSDouglas Gilbert 		if (scsi_result)
4124cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4125773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
4126cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4127773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
4128cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
4129cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
4130773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
4131cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
4132cbf67842SDouglas Gilbert 						    "report: host busy"));
4133cd62b7daSDouglas Gilbert 		if (scsi_result)
4134cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4135cd62b7daSDouglas Gilbert 		else
4136cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
41371da177e4SLinus Torvalds 	}
4138c4837394SDouglas Gilbert 	__set_bit(k, sqp->in_use_bm);
4139cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
4140c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
41411da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
4142c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
4143cbf67842SDouglas Gilbert 	cmnd->result = scsi_result;
4144a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
4145c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4146c4837394SDouglas Gilbert 	if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4147c4837394SDouglas Gilbert 		setup_inject(sqp, sqcp);
4148b01f6f83SDouglas Gilbert 	if (delta_jiff > 0 || sdebug_ndelay > 0) {
4149b333a819SDouglas Gilbert 		ktime_t kt;
4150cbf67842SDouglas Gilbert 
4151b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
415213f6b610SArnd Bergmann 			kt = ns_to_ktime((u64)delta_jiff * (NSEC_PER_SEC / HZ));
4153b333a819SDouglas Gilbert 		} else
41548b0e1953SThomas Gleixner 			kt = sdebug_ndelay;
4155a10bc12aSDouglas Gilbert 		if (NULL == sd_dp) {
4156a10bc12aSDouglas Gilbert 			sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
4157a10bc12aSDouglas Gilbert 			if (NULL == sd_dp)
4158cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
4159a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4160a10bc12aSDouglas Gilbert 			hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
4161c4837394SDouglas Gilbert 				     HRTIMER_MODE_REL_PINNED);
4162a10bc12aSDouglas Gilbert 			sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
4163c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4164c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4165cbf67842SDouglas Gilbert 		}
4166c4837394SDouglas Gilbert 		if (sdebug_statistics)
4167c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
4168c4837394SDouglas Gilbert 		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4169c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
4170a10bc12aSDouglas Gilbert 		if (NULL == sd_dp) {
4171a10bc12aSDouglas Gilbert 			sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC);
4172a10bc12aSDouglas Gilbert 			if (NULL == sd_dp)
4173cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
4174a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4175c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4176c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4177a10bc12aSDouglas Gilbert 			INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
4178cbf67842SDouglas Gilbert 		}
4179c4837394SDouglas Gilbert 		if (sdebug_statistics)
4180c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
4181a10bc12aSDouglas Gilbert 		schedule_work(&sd_dp->ew.work);
4182cbf67842SDouglas Gilbert 	}
4183f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4184f46eb0e9SDouglas Gilbert 		     (scsi_result == device_qfull_result)))
4185cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4186cbf67842SDouglas Gilbert 			    "%s: num_in_q=%d +1, %s%s\n", __func__,
4187cbf67842SDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""),
4188cbf67842SDouglas Gilbert 			    "status: TASK SET FULL");
41891da177e4SLinus Torvalds 	return 0;
4190cd62b7daSDouglas Gilbert 
4191cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
4192cd62b7daSDouglas Gilbert 	cmnd->result = scsi_result;
4193cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
4194cd62b7daSDouglas Gilbert 	return 0;
41951da177e4SLinus Torvalds }
4196cbf67842SDouglas Gilbert 
419723183910SDouglas Gilbert /* Note: The following macros create attribute files in the
419823183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
419923183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
420023183910SDouglas Gilbert    as it can when the corresponding attribute in the
420123183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
420223183910SDouglas Gilbert  */
4203773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4204773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
42059b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
4206773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
4207c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
4208773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4209773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
4210773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
4211773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4212773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4213773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4214773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4215773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
4216e5203cf0SHannes Reinecke module_param_string(inq_vendor, sdebug_inq_vendor_id,
4217e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR);
4218e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
4219e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR);
4220e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
4221e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR);
4222773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4223773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4224773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4225773642d9SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4226773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4227773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4228773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4229773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4230773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4231773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4232773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4233773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4234773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4235773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4236773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
423786e6828aSLukas Herbolt module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
4238773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4239773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4240773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4241773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
4242c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
4243773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
4244c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
4245773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4246773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4247773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4248773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4249773642d9SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
425009ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
4251773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
425223183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
4253773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
42545b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
42551da177e4SLinus Torvalds 
42561da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
42571da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
42581da177e4SLinus Torvalds MODULE_LICENSE("GPL");
4259b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
42601da177e4SLinus Torvalds 
42611da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
42625b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
42639b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
42640759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
4265cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
4266c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
42675b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
42685b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
4269c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
4270beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
427123183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
42725b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
4273185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
4274e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
4275e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
42769b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
42779b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
42785b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
42795b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
42805b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
4281760f3b03SDouglas Gilbert MODULE_PARM_DESC(lbprz,
4282760f3b03SDouglas Gilbert 	"on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
42835b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
4284c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
4285cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4286cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
4287c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
428878d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
42891da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
4290c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
429132c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
42926f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
42935b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
429486e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
42951da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
4296d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
4297760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
4298ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
4299c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
4300c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
4301c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
43025b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
43035b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
43046014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
43056014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
430609ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
430709ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
4308c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
43095b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
43105b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
43111da177e4SLinus Torvalds 
4312760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
4313760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
43141da177e4SLinus Torvalds 
43151da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp)
43161da177e4SLinus Torvalds {
4317c4837394SDouglas Gilbert 	int k;
4318c4837394SDouglas Gilbert 
4319760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4320760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
4321760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
4322c4837394SDouglas Gilbert 		return sdebug_info;
4323760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4324760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4325760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
4326760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
43271da177e4SLinus Torvalds 	return sdebug_info;
43281da177e4SLinus Torvalds }
43291da177e4SLinus Torvalds 
4330cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
4331fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4332fd32119bSDouglas Gilbert 				 int length)
43331da177e4SLinus Torvalds {
43341da177e4SLinus Torvalds 	char arr[16];
4335c8ed555aSAl Viro 	int opts;
43361da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
43371da177e4SLinus Torvalds 
43381da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
43391da177e4SLinus Torvalds 		return -EACCES;
43401da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
43411da177e4SLinus Torvalds 	arr[minLen] = '\0';
4342c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
43431da177e4SLinus Torvalds 		return -EINVAL;
4344773642d9SDouglas Gilbert 	sdebug_opts = opts;
4345773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4346773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4347773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
4348c4837394SDouglas Gilbert 		tweak_cmnd_count();
43491da177e4SLinus Torvalds 	return length;
43501da177e4SLinus Torvalds }
4351c8ed555aSAl Viro 
4352cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4353cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
4354cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
4355c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4356c8ed555aSAl Viro {
4357c4837394SDouglas Gilbert 	int f, j, l;
4358c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4359cbf67842SDouglas Gilbert 
4360c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4361c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
4362c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4363c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4364c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
4365c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4366c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4367c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
4368c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4369c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4370c4837394SDouglas Gilbert 		   num_aborts);
4371c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4372c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
4373c4837394SDouglas Gilbert 		   num_host_resets);
4374c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4375c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
4376c4837394SDouglas Gilbert 	seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n",
4377c4837394SDouglas Gilbert 		   TICK_NSEC / 1000, "statistics", sdebug_statistics,
4378c4837394SDouglas Gilbert 		   sdebug_mq_active);
4379c4837394SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4380c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
4381c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
4382c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
4383c4837394SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf));
4384cbf67842SDouglas Gilbert 
4385c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
4386c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4387c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
4388c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4389773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
4390c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4391c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
4392c4837394SDouglas Gilbert 				   "first,last bits", f, l);
4393c4837394SDouglas Gilbert 		}
4394cbf67842SDouglas Gilbert 	}
4395c8ed555aSAl Viro 	return 0;
43961da177e4SLinus Torvalds }
43971da177e4SLinus Torvalds 
439882069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
43991da177e4SLinus Torvalds {
4400c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
44011da177e4SLinus Torvalds }
4402c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4403c4837394SDouglas Gilbert  * of delay is jiffies.
4404c4837394SDouglas Gilbert  */
440582069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
440682069379SAkinobu Mita 			   size_t count)
44071da177e4SLinus Torvalds {
4408c2206098SDouglas Gilbert 	int jdelay, res;
44091da177e4SLinus Torvalds 
4410b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
4411cbf67842SDouglas Gilbert 		res = count;
4412c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
4413c4837394SDouglas Gilbert 			int j, k;
4414c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4415cbf67842SDouglas Gilbert 
4416c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4417c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4418c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4419c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4420c4837394SDouglas Gilbert 						   sdebug_max_queue);
4421c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4422c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4423c4837394SDouglas Gilbert 					break;
4424c4837394SDouglas Gilbert 				}
4425c4837394SDouglas Gilbert 			}
4426c4837394SDouglas Gilbert 			if (res > 0) {
4427a10bc12aSDouglas Gilbert 				/* make sure sdebug_defer instances get
4428a10bc12aSDouglas Gilbert 				 * re-allocated for new delay variant */
4429a10bc12aSDouglas Gilbert 				free_all_queued();
4430c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
4431773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
44321da177e4SLinus Torvalds 			}
4433c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4434cbf67842SDouglas Gilbert 		}
4435cbf67842SDouglas Gilbert 		return res;
44361da177e4SLinus Torvalds 	}
44371da177e4SLinus Torvalds 	return -EINVAL;
44381da177e4SLinus Torvalds }
443982069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
44401da177e4SLinus Torvalds 
4441cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4442cbf67842SDouglas Gilbert {
4443773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
4444cbf67842SDouglas Gilbert }
4445cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
4446c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
4447cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
4448cbf67842SDouglas Gilbert 			    size_t count)
4449cbf67842SDouglas Gilbert {
4450c4837394SDouglas Gilbert 	int ndelay, res;
4451cbf67842SDouglas Gilbert 
4452cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4453c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
4454cbf67842SDouglas Gilbert 		res = count;
4455773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
4456c4837394SDouglas Gilbert 			int j, k;
4457c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4458c4837394SDouglas Gilbert 
4459c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4460c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4461c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4462c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4463c4837394SDouglas Gilbert 						   sdebug_max_queue);
4464c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4465c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4466c4837394SDouglas Gilbert 					break;
4467c4837394SDouglas Gilbert 				}
4468c4837394SDouglas Gilbert 			}
4469c4837394SDouglas Gilbert 			if (res > 0) {
4470a10bc12aSDouglas Gilbert 				/* make sure sdebug_defer instances get
4471a10bc12aSDouglas Gilbert 				 * re-allocated for new delay variant */
4472a10bc12aSDouglas Gilbert 				free_all_queued();
4473773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
4474c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
4475c2206098SDouglas Gilbert 							: DEF_JDELAY;
4476cbf67842SDouglas Gilbert 			}
4477c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4478cbf67842SDouglas Gilbert 		}
4479cbf67842SDouglas Gilbert 		return res;
4480cbf67842SDouglas Gilbert 	}
4481cbf67842SDouglas Gilbert 	return -EINVAL;
4482cbf67842SDouglas Gilbert }
4483cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
4484cbf67842SDouglas Gilbert 
448582069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
44861da177e4SLinus Torvalds {
4487773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
44881da177e4SLinus Torvalds }
44891da177e4SLinus Torvalds 
449082069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
449182069379SAkinobu Mita 			  size_t count)
44921da177e4SLinus Torvalds {
44931da177e4SLinus Torvalds         int opts;
44941da177e4SLinus Torvalds 	char work[20];
44951da177e4SLinus Torvalds 
44961da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
449748a96876SRasmus Villemoes 		if (0 == strncasecmp(work,"0x", 2)) {
44981da177e4SLinus Torvalds 			if (1 == sscanf(&work[2], "%x", &opts))
44991da177e4SLinus Torvalds 				goto opts_done;
45001da177e4SLinus Torvalds 		} else {
45011da177e4SLinus Torvalds 			if (1 == sscanf(work, "%d", &opts))
45021da177e4SLinus Torvalds 				goto opts_done;
45031da177e4SLinus Torvalds 		}
45041da177e4SLinus Torvalds 	}
45051da177e4SLinus Torvalds 	return -EINVAL;
45061da177e4SLinus Torvalds opts_done:
4507773642d9SDouglas Gilbert 	sdebug_opts = opts;
4508773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4509773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4510c4837394SDouglas Gilbert 	tweak_cmnd_count();
45111da177e4SLinus Torvalds 	return count;
45121da177e4SLinus Torvalds }
451382069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
45141da177e4SLinus Torvalds 
451582069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
45161da177e4SLinus Torvalds {
4517773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
45181da177e4SLinus Torvalds }
451982069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
452082069379SAkinobu Mita 			   size_t count)
45211da177e4SLinus Torvalds {
45221da177e4SLinus Torvalds         int n;
45231da177e4SLinus Torvalds 
45241da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4525773642d9SDouglas Gilbert 		sdebug_ptype = n;
45261da177e4SLinus Torvalds 		return count;
45271da177e4SLinus Torvalds 	}
45281da177e4SLinus Torvalds 	return -EINVAL;
45291da177e4SLinus Torvalds }
453082069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
45311da177e4SLinus Torvalds 
453282069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
45331da177e4SLinus Torvalds {
4534773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
45351da177e4SLinus Torvalds }
453682069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
453782069379SAkinobu Mita 			    size_t count)
45381da177e4SLinus Torvalds {
45391da177e4SLinus Torvalds         int n;
45401da177e4SLinus Torvalds 
45411da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4542773642d9SDouglas Gilbert 		sdebug_dsense = n;
45431da177e4SLinus Torvalds 		return count;
45441da177e4SLinus Torvalds 	}
45451da177e4SLinus Torvalds 	return -EINVAL;
45461da177e4SLinus Torvalds }
454782069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
45481da177e4SLinus Torvalds 
454982069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
455023183910SDouglas Gilbert {
4551773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
455223183910SDouglas Gilbert }
455382069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
455482069379SAkinobu Mita 			     size_t count)
455523183910SDouglas Gilbert {
455623183910SDouglas Gilbert         int n;
455723183910SDouglas Gilbert 
455823183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4559cbf67842SDouglas Gilbert 		n = (n > 0);
4560773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
4561773642d9SDouglas Gilbert 		if (sdebug_fake_rw != n) {
4562cbf67842SDouglas Gilbert 			if ((0 == n) && (NULL == fake_storep)) {
4563cbf67842SDouglas Gilbert 				unsigned long sz =
4564773642d9SDouglas Gilbert 					(unsigned long)sdebug_dev_size_mb *
4565cbf67842SDouglas Gilbert 					1048576;
4566cbf67842SDouglas Gilbert 
4567cbf67842SDouglas Gilbert 				fake_storep = vmalloc(sz);
4568cbf67842SDouglas Gilbert 				if (NULL == fake_storep) {
4569c1287970STomas Winkler 					pr_err("out of memory, 9\n");
4570cbf67842SDouglas Gilbert 					return -ENOMEM;
4571cbf67842SDouglas Gilbert 				}
4572cbf67842SDouglas Gilbert 				memset(fake_storep, 0, sz);
4573cbf67842SDouglas Gilbert 			}
4574773642d9SDouglas Gilbert 			sdebug_fake_rw = n;
4575cbf67842SDouglas Gilbert 		}
457623183910SDouglas Gilbert 		return count;
457723183910SDouglas Gilbert 	}
457823183910SDouglas Gilbert 	return -EINVAL;
457923183910SDouglas Gilbert }
458082069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
458123183910SDouglas Gilbert 
458282069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
4583c65b1445SDouglas Gilbert {
4584773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
4585c65b1445SDouglas Gilbert }
458682069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
458782069379SAkinobu Mita 			      size_t count)
4588c65b1445SDouglas Gilbert {
4589c65b1445SDouglas Gilbert         int n;
4590c65b1445SDouglas Gilbert 
4591c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4592773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
4593c65b1445SDouglas Gilbert 		return count;
4594c65b1445SDouglas Gilbert 	}
4595c65b1445SDouglas Gilbert 	return -EINVAL;
4596c65b1445SDouglas Gilbert }
459782069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
4598c65b1445SDouglas Gilbert 
459982069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
46001da177e4SLinus Torvalds {
4601773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
46021da177e4SLinus Torvalds }
460382069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
460482069379SAkinobu Mita 			      size_t count)
46051da177e4SLinus Torvalds {
46061da177e4SLinus Torvalds         int n;
46071da177e4SLinus Torvalds 
46081da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4609773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
46101da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
46111da177e4SLinus Torvalds 		return count;
46121da177e4SLinus Torvalds 	}
46131da177e4SLinus Torvalds 	return -EINVAL;
46141da177e4SLinus Torvalds }
461582069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
46161da177e4SLinus Torvalds 
461782069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
46181da177e4SLinus Torvalds {
4619773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
46201da177e4SLinus Torvalds }
462182069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
46221da177e4SLinus Torvalds 
462382069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
46241da177e4SLinus Torvalds {
4625773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
46261da177e4SLinus Torvalds }
462782069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
46281da177e4SLinus Torvalds 
462982069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
46301da177e4SLinus Torvalds {
4631773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
46321da177e4SLinus Torvalds }
463382069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
463482069379SAkinobu Mita 			       size_t count)
46351da177e4SLinus Torvalds {
46361da177e4SLinus Torvalds         int nth;
46371da177e4SLinus Torvalds 
46381da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
4639773642d9SDouglas Gilbert 		sdebug_every_nth = nth;
4640c4837394SDouglas Gilbert 		if (nth && !sdebug_statistics) {
4641c4837394SDouglas Gilbert 			pr_info("every_nth needs statistics=1, set it\n");
4642c4837394SDouglas Gilbert 			sdebug_statistics = true;
4643c4837394SDouglas Gilbert 		}
4644c4837394SDouglas Gilbert 		tweak_cmnd_count();
46451da177e4SLinus Torvalds 		return count;
46461da177e4SLinus Torvalds 	}
46471da177e4SLinus Torvalds 	return -EINVAL;
46481da177e4SLinus Torvalds }
464982069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
46501da177e4SLinus Torvalds 
465182069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
46521da177e4SLinus Torvalds {
4653773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
46541da177e4SLinus Torvalds }
465582069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
465682069379SAkinobu Mita 			      size_t count)
46571da177e4SLinus Torvalds {
46581da177e4SLinus Torvalds         int n;
465919c8ead7SEwan D. Milne 	bool changed;
46601da177e4SLinus Torvalds 
46611da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
46628d039e22SDouglas Gilbert 		if (n > 256) {
46638d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
46648d039e22SDouglas Gilbert 			return -EINVAL;
46658d039e22SDouglas Gilbert 		}
4666773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
4667773642d9SDouglas Gilbert 		sdebug_max_luns = n;
46681da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
4669773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
467019c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
467119c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
467219c8ead7SEwan D. Milne 
467319c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
467419c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
467519c8ead7SEwan D. Milne 					    host_list) {
467619c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
467719c8ead7SEwan D. Milne 						    dev_list) {
467819c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
467919c8ead7SEwan D. Milne 						dp->uas_bm);
468019c8ead7SEwan D. Milne 				}
468119c8ead7SEwan D. Milne 			}
468219c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
468319c8ead7SEwan D. Milne 		}
46841da177e4SLinus Torvalds 		return count;
46851da177e4SLinus Torvalds 	}
46861da177e4SLinus Torvalds 	return -EINVAL;
46871da177e4SLinus Torvalds }
468882069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
46891da177e4SLinus Torvalds 
469082069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
469178d4e5a0SDouglas Gilbert {
4692773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
469378d4e5a0SDouglas Gilbert }
4694cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
4695cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
469682069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
469782069379SAkinobu Mita 			       size_t count)
469878d4e5a0SDouglas Gilbert {
4699c4837394SDouglas Gilbert 	int j, n, k, a;
4700c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
470178d4e5a0SDouglas Gilbert 
470278d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
4703c4837394SDouglas Gilbert 	    (n <= SDEBUG_CANQUEUE)) {
4704c4837394SDouglas Gilbert 		block_unblock_all_queues(true);
4705c4837394SDouglas Gilbert 		k = 0;
4706c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4707c4837394SDouglas Gilbert 		     ++j, ++sqp) {
4708c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4709c4837394SDouglas Gilbert 			if (a > k)
4710c4837394SDouglas Gilbert 				k = a;
4711c4837394SDouglas Gilbert 		}
4712773642d9SDouglas Gilbert 		sdebug_max_queue = n;
4713c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
4714cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4715cbf67842SDouglas Gilbert 		else if (k >= n)
4716cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4717cbf67842SDouglas Gilbert 		else
4718cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4719c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
472078d4e5a0SDouglas Gilbert 		return count;
472178d4e5a0SDouglas Gilbert 	}
472278d4e5a0SDouglas Gilbert 	return -EINVAL;
472378d4e5a0SDouglas Gilbert }
472482069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
472578d4e5a0SDouglas Gilbert 
472682069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
472778d4e5a0SDouglas Gilbert {
4728773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
472978d4e5a0SDouglas Gilbert }
473082069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
473178d4e5a0SDouglas Gilbert 
473282069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
47331da177e4SLinus Torvalds {
4734773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
47351da177e4SLinus Torvalds }
473682069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
47371da177e4SLinus Torvalds 
473882069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
4739c65b1445SDouglas Gilbert {
4740773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
4741c65b1445SDouglas Gilbert }
474282069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
474382069379SAkinobu Mita 				size_t count)
4744c65b1445SDouglas Gilbert {
4745c65b1445SDouglas Gilbert         int n;
47460d01c5dfSDouglas Gilbert 	bool changed;
4747c65b1445SDouglas Gilbert 
4748c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4749773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
4750773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
475128898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
47520d01c5dfSDouglas Gilbert 		if (changed) {
47530d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
47540d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
475528898873SFUJITA Tomonori 
47564bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
47570d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
47580d01c5dfSDouglas Gilbert 					    host_list) {
47590d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
47600d01c5dfSDouglas Gilbert 						    dev_list) {
47610d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
47620d01c5dfSDouglas Gilbert 						dp->uas_bm);
47630d01c5dfSDouglas Gilbert 				}
47640d01c5dfSDouglas Gilbert 			}
47654bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
47660d01c5dfSDouglas Gilbert 		}
4767c65b1445SDouglas Gilbert 		return count;
4768c65b1445SDouglas Gilbert 	}
4769c65b1445SDouglas Gilbert 	return -EINVAL;
4770c65b1445SDouglas Gilbert }
477182069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
4772c65b1445SDouglas Gilbert 
477382069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
47741da177e4SLinus Torvalds {
4775773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
47761da177e4SLinus Torvalds }
47771da177e4SLinus Torvalds 
4778fd32119bSDouglas Gilbert static int sdebug_add_adapter(void);
4779fd32119bSDouglas Gilbert static void sdebug_remove_adapter(void);
4780fd32119bSDouglas Gilbert 
478182069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
478282069379SAkinobu Mita 			      size_t count)
47831da177e4SLinus Torvalds {
47841da177e4SLinus Torvalds 	int delta_hosts;
47851da177e4SLinus Torvalds 
4786f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
47871da177e4SLinus Torvalds 		return -EINVAL;
47881da177e4SLinus Torvalds 	if (delta_hosts > 0) {
47891da177e4SLinus Torvalds 		do {
47901da177e4SLinus Torvalds 			sdebug_add_adapter();
47911da177e4SLinus Torvalds 		} while (--delta_hosts);
47921da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
47931da177e4SLinus Torvalds 		do {
47941da177e4SLinus Torvalds 			sdebug_remove_adapter();
47951da177e4SLinus Torvalds 		} while (++delta_hosts);
47961da177e4SLinus Torvalds 	}
47971da177e4SLinus Torvalds 	return count;
47981da177e4SLinus Torvalds }
479982069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
48001da177e4SLinus Torvalds 
480182069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
480223183910SDouglas Gilbert {
4803773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
480423183910SDouglas Gilbert }
480582069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
480682069379SAkinobu Mita 				    size_t count)
480723183910SDouglas Gilbert {
480823183910SDouglas Gilbert 	int n;
480923183910SDouglas Gilbert 
481023183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4811773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
481223183910SDouglas Gilbert 		return count;
481323183910SDouglas Gilbert 	}
481423183910SDouglas Gilbert 	return -EINVAL;
481523183910SDouglas Gilbert }
481682069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
481723183910SDouglas Gilbert 
4818c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
4819c4837394SDouglas Gilbert {
4820c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
4821c4837394SDouglas Gilbert }
4822c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
4823c4837394SDouglas Gilbert 				size_t count)
4824c4837394SDouglas Gilbert {
4825c4837394SDouglas Gilbert 	int n;
4826c4837394SDouglas Gilbert 
4827c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
4828c4837394SDouglas Gilbert 		if (n > 0)
4829c4837394SDouglas Gilbert 			sdebug_statistics = true;
4830c4837394SDouglas Gilbert 		else {
4831c4837394SDouglas Gilbert 			clear_queue_stats();
4832c4837394SDouglas Gilbert 			sdebug_statistics = false;
4833c4837394SDouglas Gilbert 		}
4834c4837394SDouglas Gilbert 		return count;
4835c4837394SDouglas Gilbert 	}
4836c4837394SDouglas Gilbert 	return -EINVAL;
4837c4837394SDouglas Gilbert }
4838c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
4839c4837394SDouglas Gilbert 
484082069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
4841597136abSMartin K. Petersen {
4842773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
4843597136abSMartin K. Petersen }
484482069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
4845597136abSMartin K. Petersen 
4846c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
4847c4837394SDouglas Gilbert {
4848c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
4849c4837394SDouglas Gilbert }
4850c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
4851c4837394SDouglas Gilbert 
485282069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
4853c6a44287SMartin K. Petersen {
4854773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
4855c6a44287SMartin K. Petersen }
485682069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
4857c6a44287SMartin K. Petersen 
485882069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
4859c6a44287SMartin K. Petersen {
4860773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
4861c6a44287SMartin K. Petersen }
486282069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
4863c6a44287SMartin K. Petersen 
486482069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
4865c6a44287SMartin K. Petersen {
4866773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
4867c6a44287SMartin K. Petersen }
486882069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
4869c6a44287SMartin K. Petersen 
487082069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
4871c6a44287SMartin K. Petersen {
4872773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
4873c6a44287SMartin K. Petersen }
487482069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
4875c6a44287SMartin K. Petersen 
487682069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
487744d92694SMartin K. Petersen {
487844d92694SMartin K. Petersen 	ssize_t count;
487944d92694SMartin K. Petersen 
48805b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
488144d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
488244d92694SMartin K. Petersen 				 sdebug_store_sectors);
488344d92694SMartin K. Petersen 
4884c7badc90STejun Heo 	count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
4885c7badc90STejun Heo 			  (int)map_size, map_storep);
488644d92694SMartin K. Petersen 	buf[count++] = '\n';
4887c7badc90STejun Heo 	buf[count] = '\0';
488844d92694SMartin K. Petersen 
488944d92694SMartin K. Petersen 	return count;
489044d92694SMartin K. Petersen }
489182069379SAkinobu Mita static DRIVER_ATTR_RO(map);
489244d92694SMartin K. Petersen 
489382069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
4894d986788bSMartin Pitt {
4895773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
4896d986788bSMartin Pitt }
489782069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
489882069379SAkinobu Mita 			       size_t count)
4899d986788bSMartin Pitt {
4900d986788bSMartin Pitt 	int n;
4901d986788bSMartin Pitt 
4902d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4903773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
4904d986788bSMartin Pitt 		return count;
4905d986788bSMartin Pitt 	}
4906d986788bSMartin Pitt 	return -EINVAL;
4907d986788bSMartin Pitt }
490882069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
4909d986788bSMartin Pitt 
4910cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4911cbf67842SDouglas Gilbert {
4912773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
4913cbf67842SDouglas Gilbert }
4914185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
4915cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4916cbf67842SDouglas Gilbert 			       size_t count)
4917cbf67842SDouglas Gilbert {
4918185dd232SDouglas Gilbert 	int n;
4919cbf67842SDouglas Gilbert 
4920cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4921185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
4922185dd232SDouglas Gilbert 		return count;
4923cbf67842SDouglas Gilbert 	}
4924cbf67842SDouglas Gilbert 	return -EINVAL;
4925cbf67842SDouglas Gilbert }
4926cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
4927cbf67842SDouglas Gilbert 
4928c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
4929c2248fc9SDouglas Gilbert {
4930773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
4931c2248fc9SDouglas Gilbert }
4932c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4933c2248fc9SDouglas Gilbert 			    size_t count)
4934c2248fc9SDouglas Gilbert {
4935c2248fc9SDouglas Gilbert 	int n;
4936c2248fc9SDouglas Gilbert 
4937c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4938773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
4939c2248fc9SDouglas Gilbert 		return count;
4940c2248fc9SDouglas Gilbert 	}
4941c2248fc9SDouglas Gilbert 	return -EINVAL;
4942c2248fc9SDouglas Gilbert }
4943c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
4944c2248fc9SDouglas Gilbert 
494509ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
494609ba24c1SDouglas Gilbert {
494709ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
494809ba24c1SDouglas Gilbert }
494909ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
495009ba24c1SDouglas Gilbert 
49519b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
49529b760fd8SDouglas Gilbert {
49539b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
49549b760fd8SDouglas Gilbert }
49559b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
49569b760fd8SDouglas Gilbert 			     size_t count)
49579b760fd8SDouglas Gilbert {
49589b760fd8SDouglas Gilbert 	int ret, n;
49599b760fd8SDouglas Gilbert 
49609b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
49619b760fd8SDouglas Gilbert 	if (ret)
49629b760fd8SDouglas Gilbert 		return ret;
49639b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
49649b760fd8SDouglas Gilbert 	all_config_cdb_len();
49659b760fd8SDouglas Gilbert 	return count;
49669b760fd8SDouglas Gilbert }
49679b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
49689b760fd8SDouglas Gilbert 
4969cbf67842SDouglas Gilbert 
497082069379SAkinobu Mita /* Note: The following array creates attribute files in the
497123183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
497223183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
497323183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
497423183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
497523183910SDouglas Gilbert  */
49766ecaff7fSRandy Dunlap 
497782069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
497882069379SAkinobu Mita 	&driver_attr_delay.attr,
497982069379SAkinobu Mita 	&driver_attr_opts.attr,
498082069379SAkinobu Mita 	&driver_attr_ptype.attr,
498182069379SAkinobu Mita 	&driver_attr_dsense.attr,
498282069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
498382069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
498482069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
498582069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
498682069379SAkinobu Mita 	&driver_attr_num_parts.attr,
498782069379SAkinobu Mita 	&driver_attr_every_nth.attr,
498882069379SAkinobu Mita 	&driver_attr_max_luns.attr,
498982069379SAkinobu Mita 	&driver_attr_max_queue.attr,
499082069379SAkinobu Mita 	&driver_attr_no_uld.attr,
499182069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
499282069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
499382069379SAkinobu Mita 	&driver_attr_add_host.attr,
499482069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
499582069379SAkinobu Mita 	&driver_attr_sector_size.attr,
4996c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
4997c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
499882069379SAkinobu Mita 	&driver_attr_dix.attr,
499982069379SAkinobu Mita 	&driver_attr_dif.attr,
500082069379SAkinobu Mita 	&driver_attr_guard.attr,
500182069379SAkinobu Mita 	&driver_attr_ato.attr,
500282069379SAkinobu Mita 	&driver_attr_map.attr,
500382069379SAkinobu Mita 	&driver_attr_removable.attr,
5004cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
5005cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
5006c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
500709ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
50089b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
500982069379SAkinobu Mita 	NULL,
501082069379SAkinobu Mita };
501182069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
50121da177e4SLinus Torvalds 
501311ddcecaSAkinobu Mita static struct device *pseudo_primary;
50148dea0d02SFUJITA Tomonori 
50151da177e4SLinus Torvalds static int __init scsi_debug_init(void)
50161da177e4SLinus Torvalds {
50175f2578e5SFUJITA Tomonori 	unsigned long sz;
50181da177e4SLinus Torvalds 	int host_to_add;
50191da177e4SLinus Torvalds 	int k;
50206ecaff7fSRandy Dunlap 	int ret;
50211da177e4SLinus Torvalds 
5022cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
5023cbf67842SDouglas Gilbert 
5024773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
5025c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
5026773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
5027773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
5028c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
5029cbf67842SDouglas Gilbert 
5030773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
5031597136abSMartin K. Petersen 	case  512:
5032597136abSMartin K. Petersen 	case 1024:
5033597136abSMartin K. Petersen 	case 2048:
5034597136abSMartin K. Petersen 	case 4096:
5035597136abSMartin K. Petersen 		break;
5036597136abSMartin K. Petersen 	default:
5037773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
5038597136abSMartin K. Petersen 		return -EINVAL;
5039597136abSMartin K. Petersen 	}
5040597136abSMartin K. Petersen 
5041773642d9SDouglas Gilbert 	switch (sdebug_dif) {
50428475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
5043f46eb0e9SDouglas Gilbert 		break;
50448475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
50458475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
50468475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
5047f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
5048c6a44287SMartin K. Petersen 		break;
5049c6a44287SMartin K. Petersen 
5050c6a44287SMartin K. Petersen 	default:
5051c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
5052c6a44287SMartin K. Petersen 		return -EINVAL;
5053c6a44287SMartin K. Petersen 	}
5054c6a44287SMartin K. Petersen 
5055773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
5056c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
5057c6a44287SMartin K. Petersen 		return -EINVAL;
5058c6a44287SMartin K. Petersen 	}
5059c6a44287SMartin K. Petersen 
5060773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
5061c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
5062c6a44287SMartin K. Petersen 		return -EINVAL;
5063c6a44287SMartin K. Petersen 	}
5064c6a44287SMartin K. Petersen 
5065773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
5066773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
5067ea61fca5SMartin K. Petersen 		return -EINVAL;
5068ea61fca5SMartin K. Petersen 	}
50698d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
50708d039e22SDouglas Gilbert 		pr_warn("max_luns can be no more than 256, use default\n");
50718d039e22SDouglas Gilbert 		sdebug_max_luns = DEF_MAX_LUNS;
50728d039e22SDouglas Gilbert 	}
5073ea61fca5SMartin K. Petersen 
5074773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
5075773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
5076ea61fca5SMartin K. Petersen 		return -EINVAL;
5077ea61fca5SMartin K. Petersen 	}
5078ea61fca5SMartin K. Petersen 
5079c4837394SDouglas Gilbert 	if (submit_queues < 1) {
5080c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
5081c4837394SDouglas Gilbert 		return -EINVAL;
5082c4837394SDouglas Gilbert 	}
5083c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
5084c4837394SDouglas Gilbert 			       GFP_KERNEL);
5085c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
5086c4837394SDouglas Gilbert 		return -ENOMEM;
5087c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
5088c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
5089c4837394SDouglas Gilbert 
5090773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
5091773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
5092773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
5093773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
509428898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
50951da177e4SLinus Torvalds 
50961da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
50971da177e4SLinus Torvalds 	sdebug_heads = 8;
50981da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
5099773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
51001da177e4SLinus Torvalds 		sdebug_heads = 64;
5101773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
5102fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
51031da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
51041da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
51051da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
51061da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
51071da177e4SLinus Torvalds 		sdebug_heads = 255;
51081da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
51091da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
51101da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
51111da177e4SLinus Torvalds 	}
51121da177e4SLinus Torvalds 
5113b01f6f83SDouglas Gilbert 	if (sdebug_fake_rw == 0) {
51141da177e4SLinus Torvalds 		fake_storep = vmalloc(sz);
51151da177e4SLinus Torvalds 		if (NULL == fake_storep) {
5116c1287970STomas Winkler 			pr_err("out of memory, 1\n");
5117c4837394SDouglas Gilbert 			ret = -ENOMEM;
5118c4837394SDouglas Gilbert 			goto free_q_arr;
51191da177e4SLinus Torvalds 		}
51201da177e4SLinus Torvalds 		memset(fake_storep, 0, sz);
5121773642d9SDouglas Gilbert 		if (sdebug_num_parts > 0)
5122f58b0efbSFUJITA Tomonori 			sdebug_build_parts(fake_storep, sz);
5123cbf67842SDouglas Gilbert 	}
51241da177e4SLinus Torvalds 
5125773642d9SDouglas Gilbert 	if (sdebug_dix) {
5126c6a44287SMartin K. Petersen 		int dif_size;
5127c6a44287SMartin K. Petersen 
51286ebf105cSChristoph Hellwig 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
5129c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
5130c6a44287SMartin K. Petersen 
5131c1287970STomas Winkler 		pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
5132c6a44287SMartin K. Petersen 
5133c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
5134c1287970STomas Winkler 			pr_err("out of mem. (DIX)\n");
5135c6a44287SMartin K. Petersen 			ret = -ENOMEM;
5136c6a44287SMartin K. Petersen 			goto free_vm;
5137c6a44287SMartin K. Petersen 		}
5138c6a44287SMartin K. Petersen 
5139c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
5140c6a44287SMartin K. Petersen 	}
5141c6a44287SMartin K. Petersen 
51425b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
51435b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
5144773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
5145773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
51466014759cSMartin K. Petersen 
5147773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
5148773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
51496014759cSMartin K. Petersen 
5150773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
5151773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
51526014759cSMartin K. Petersen 
5153773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
5154773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
5155773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
5156c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
5157c4837394SDouglas Gilbert 			ret = -EINVAL;
5158c4837394SDouglas Gilbert 			goto free_vm;
515944d92694SMartin K. Petersen 		}
516044d92694SMartin K. Petersen 
5161b90ebc3dSAkinobu Mita 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
5162b90ebc3dSAkinobu Mita 		map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
516344d92694SMartin K. Petersen 
5164c1287970STomas Winkler 		pr_info("%lu provisioning blocks\n", map_size);
516544d92694SMartin K. Petersen 
516644d92694SMartin K. Petersen 		if (map_storep == NULL) {
5167c1287970STomas Winkler 			pr_err("out of mem. (MAP)\n");
516844d92694SMartin K. Petersen 			ret = -ENOMEM;
516944d92694SMartin K. Petersen 			goto free_vm;
517044d92694SMartin K. Petersen 		}
517144d92694SMartin K. Petersen 
5172b90ebc3dSAkinobu Mita 		bitmap_zero(map_storep, map_size);
517344d92694SMartin K. Petersen 
517444d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
5175773642d9SDouglas Gilbert 		if (sdebug_num_parts)
517644d92694SMartin K. Petersen 			map_region(0, 2);
517744d92694SMartin K. Petersen 	}
517844d92694SMartin K. Petersen 
51799b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
51809b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
5181c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
51829b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
51836ecaff7fSRandy Dunlap 		goto free_vm;
51846ecaff7fSRandy Dunlap 	}
51856ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
51866ecaff7fSRandy Dunlap 	if (ret < 0) {
5187c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
51886ecaff7fSRandy Dunlap 		goto dev_unreg;
51896ecaff7fSRandy Dunlap 	}
51906ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
51916ecaff7fSRandy Dunlap 	if (ret < 0) {
5192c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
51936ecaff7fSRandy Dunlap 		goto bus_unreg;
51946ecaff7fSRandy Dunlap 	}
51951da177e4SLinus Torvalds 
5196773642d9SDouglas Gilbert 	host_to_add = sdebug_add_host;
5197773642d9SDouglas Gilbert 	sdebug_add_host = 0;
51981da177e4SLinus Torvalds 
51991da177e4SLinus Torvalds         for (k = 0; k < host_to_add; k++) {
52001da177e4SLinus Torvalds                 if (sdebug_add_adapter()) {
5201c1287970STomas Winkler 			pr_err("sdebug_add_adapter failed k=%d\n", k);
52021da177e4SLinus Torvalds                         break;
52031da177e4SLinus Torvalds                 }
52041da177e4SLinus Torvalds         }
52051da177e4SLinus Torvalds 
5206773642d9SDouglas Gilbert 	if (sdebug_verbose)
5207773642d9SDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_add_host);
5208c1287970STomas Winkler 
52091da177e4SLinus Torvalds 	return 0;
52106ecaff7fSRandy Dunlap 
52116ecaff7fSRandy Dunlap bus_unreg:
52126ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
52136ecaff7fSRandy Dunlap dev_unreg:
52149b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
52156ecaff7fSRandy Dunlap free_vm:
521644d92694SMartin K. Petersen 	vfree(map_storep);
5217c6a44287SMartin K. Petersen 	vfree(dif_storep);
52186ecaff7fSRandy Dunlap 	vfree(fake_storep);
5219c4837394SDouglas Gilbert free_q_arr:
5220c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
52216ecaff7fSRandy Dunlap 	return ret;
52221da177e4SLinus Torvalds }
52231da177e4SLinus Torvalds 
52241da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
52251da177e4SLinus Torvalds {
5226773642d9SDouglas Gilbert 	int k = sdebug_add_host;
52271da177e4SLinus Torvalds 
52281da177e4SLinus Torvalds 	stop_all_queued();
5229cbf67842SDouglas Gilbert 	free_all_queued();
52301da177e4SLinus Torvalds 	for (; k; k--)
52311da177e4SLinus Torvalds 		sdebug_remove_adapter();
52321da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
52331da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
52349b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
52351da177e4SLinus Torvalds 
52364d2b496fSEwan D. Milne 	vfree(map_storep);
5237c6a44287SMartin K. Petersen 	vfree(dif_storep);
52381da177e4SLinus Torvalds 	vfree(fake_storep);
5239c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
52401da177e4SLinus Torvalds }
52411da177e4SLinus Torvalds 
52421da177e4SLinus Torvalds device_initcall(scsi_debug_init);
52431da177e4SLinus Torvalds module_exit(scsi_debug_exit);
52441da177e4SLinus Torvalds 
52451da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev)
52461da177e4SLinus Torvalds {
52471da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
52481da177e4SLinus Torvalds 
52491da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
52501da177e4SLinus Torvalds         kfree(sdbg_host);
52511da177e4SLinus Torvalds }
52521da177e4SLinus Torvalds 
52531da177e4SLinus Torvalds static int sdebug_add_adapter(void)
52541da177e4SLinus Torvalds {
52551da177e4SLinus Torvalds 	int k, devs_per_host;
52561da177e4SLinus Torvalds         int error = 0;
52571da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
52588b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
52591da177e4SLinus Torvalds 
526024669f75SJes Sorensen         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
52611da177e4SLinus Torvalds         if (NULL == sdbg_host) {
5262c1287970STomas Winkler 		pr_err("out of memory at line %d\n", __LINE__);
52631da177e4SLinus Torvalds                 return -ENOMEM;
52641da177e4SLinus Torvalds         }
52651da177e4SLinus Torvalds 
52661da177e4SLinus Torvalds         INIT_LIST_HEAD(&sdbg_host->dev_info_list);
52671da177e4SLinus Torvalds 
5268773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
52691da177e4SLinus Torvalds         for (k = 0; k < devs_per_host; k++) {
52705cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
52715cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
5272c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
52731da177e4SLinus Torvalds                         error = -ENOMEM;
52741da177e4SLinus Torvalds 			goto clean;
52751da177e4SLinus Torvalds                 }
52761da177e4SLinus Torvalds         }
52771da177e4SLinus Torvalds 
52781da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
52791da177e4SLinus Torvalds         list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
52801da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
52811da177e4SLinus Torvalds 
52821da177e4SLinus Torvalds         sdbg_host->dev.bus = &pseudo_lld_bus;
52839b906779SNicholas Bellinger         sdbg_host->dev.parent = pseudo_primary;
52841da177e4SLinus Torvalds         sdbg_host->dev.release = &sdebug_release_adapter;
5285773642d9SDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
52861da177e4SLinus Torvalds 
52871da177e4SLinus Torvalds         error = device_register(&sdbg_host->dev);
52881da177e4SLinus Torvalds 
52891da177e4SLinus Torvalds         if (error)
52901da177e4SLinus Torvalds 		goto clean;
52911da177e4SLinus Torvalds 
5292773642d9SDouglas Gilbert 	++sdebug_add_host;
52931da177e4SLinus Torvalds         return error;
52941da177e4SLinus Torvalds 
52951da177e4SLinus Torvalds clean:
52968b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
52978b40228fSFUJITA Tomonori 				 dev_list) {
52981da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
52991da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
53001da177e4SLinus Torvalds 	}
53011da177e4SLinus Torvalds 
53021da177e4SLinus Torvalds 	kfree(sdbg_host);
53031da177e4SLinus Torvalds         return error;
53041da177e4SLinus Torvalds }
53051da177e4SLinus Torvalds 
53061da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
53071da177e4SLinus Torvalds {
53081da177e4SLinus Torvalds         struct sdebug_host_info * sdbg_host = NULL;
53091da177e4SLinus Torvalds 
53101da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
53111da177e4SLinus Torvalds         if (!list_empty(&sdebug_host_list)) {
53121da177e4SLinus Torvalds                 sdbg_host = list_entry(sdebug_host_list.prev,
53131da177e4SLinus Torvalds                                        struct sdebug_host_info, host_list);
53141da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
53151da177e4SLinus Torvalds 	}
53161da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
53171da177e4SLinus Torvalds 
53181da177e4SLinus Torvalds 	if (!sdbg_host)
53191da177e4SLinus Torvalds 		return;
53201da177e4SLinus Torvalds 
53211da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
5322773642d9SDouglas Gilbert 	--sdebug_add_host;
53231da177e4SLinus Torvalds }
53241da177e4SLinus Torvalds 
5325fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
5326cbf67842SDouglas Gilbert {
5327cbf67842SDouglas Gilbert 	int num_in_q = 0;
5328cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5329cbf67842SDouglas Gilbert 
5330c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
5331cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
5332cbf67842SDouglas Gilbert 	if (NULL == devip) {
5333c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
5334cbf67842SDouglas Gilbert 		return	-ENODEV;
5335cbf67842SDouglas Gilbert 	}
5336cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5337c40ecc12SChristoph Hellwig 
5338cbf67842SDouglas Gilbert 	if (qdepth < 1)
5339cbf67842SDouglas Gilbert 		qdepth = 1;
5340c4837394SDouglas Gilbert 	/* allow to exceed max host qc_arr elements for testing */
5341c4837394SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE + 10)
5342c4837394SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE + 10;
5343db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
5344cbf67842SDouglas Gilbert 
5345773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
5346c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
5347c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
5348cbf67842SDouglas Gilbert 	}
5349c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
5350cbf67842SDouglas Gilbert 	return sdev->queue_depth;
5351cbf67842SDouglas Gilbert }
5352cbf67842SDouglas Gilbert 
5353c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
5354817fd66bSDouglas Gilbert {
5355c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
5356773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
5357773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
5358773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
5359c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
5360773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
5361817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
5362c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
5363817fd66bSDouglas Gilbert 	}
5364c4837394SDouglas Gilbert 	return false;
5365817fd66bSDouglas Gilbert }
5366817fd66bSDouglas Gilbert 
53677ee6d1b4SBart Van Assche static bool fake_host_busy(struct scsi_cmnd *scp)
53687ee6d1b4SBart Van Assche {
53697ee6d1b4SBart Van Assche 	return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
53707ee6d1b4SBart Van Assche 		(atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
53717ee6d1b4SBart Van Assche }
53727ee6d1b4SBart Van Assche 
5373fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5374fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
5375c2248fc9SDouglas Gilbert {
5376c2248fc9SDouglas Gilbert 	u8 sdeb_i;
5377c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
5378c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
5379c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
5380c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
5381c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
5382c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5383c2248fc9SDouglas Gilbert 	int k, na;
5384c2248fc9SDouglas Gilbert 	int errsts = 0;
5385c2248fc9SDouglas Gilbert 	u32 flags;
5386c2248fc9SDouglas Gilbert 	u16 sa;
5387c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
5388c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
5389c2248fc9SDouglas Gilbert 
5390c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
5391c4837394SDouglas Gilbert 	if (sdebug_statistics)
5392c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
5393f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
5394f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
5395c2248fc9SDouglas Gilbert 		char b[120];
5396c2248fc9SDouglas Gilbert 		int n, len, sb;
5397c2248fc9SDouglas Gilbert 
5398c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
5399c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
5400c2248fc9SDouglas Gilbert 		if (len > 32)
5401c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
5402c2248fc9SDouglas Gilbert 		else {
5403c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
5404c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
5405c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
5406c2248fc9SDouglas Gilbert 		}
5407c4837394SDouglas Gilbert 		if (sdebug_mq_active)
5408c4837394SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n",
5409c4837394SDouglas Gilbert 				    my_name, blk_mq_unique_tag(scp->request),
5410c4837394SDouglas Gilbert 				    b);
5411c4837394SDouglas Gilbert 		else
5412c4837394SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name,
5413c4837394SDouglas Gilbert 				    b);
5414c2248fc9SDouglas Gilbert 	}
54157ee6d1b4SBart Van Assche 	if (fake_host_busy(scp))
54167ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
541734d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
5418f46eb0e9SDouglas Gilbert 	if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5419f46eb0e9SDouglas Gilbert 		goto err_out;
5420c2248fc9SDouglas Gilbert 
5421c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
5422c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
5423c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
5424f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
5425f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5426c2248fc9SDouglas Gilbert 		if (NULL == devip)
5427f46eb0e9SDouglas Gilbert 			goto err_out;
5428c2248fc9SDouglas Gilbert 	}
5429c2248fc9SDouglas Gilbert 	na = oip->num_attached;
5430c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
5431c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
5432c2248fc9SDouglas Gilbert 		r_oip = oip;
5433c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
5434c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
5435c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
5436c2248fc9SDouglas Gilbert 			else
5437c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
5438c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5439c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
5440c2248fc9SDouglas Gilbert 					break;
5441c2248fc9SDouglas Gilbert 			}
5442c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
5443c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5444c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
5445c2248fc9SDouglas Gilbert 					break;
5446c2248fc9SDouglas Gilbert 			}
5447c2248fc9SDouglas Gilbert 		}
5448c2248fc9SDouglas Gilbert 		if (k > na) {
5449c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
5450c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5451c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
5452c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5453c2248fc9SDouglas Gilbert 			else
5454c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
5455c2248fc9SDouglas Gilbert 			goto check_cond;
5456c2248fc9SDouglas Gilbert 		}
5457c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
5458c2248fc9SDouglas Gilbert 	flags = oip->flags;
5459f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
5460c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5461c2248fc9SDouglas Gilbert 		goto check_cond;
5462c2248fc9SDouglas Gilbert 	}
5463f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
5464773642d9SDouglas Gilbert 		if (sdebug_verbose)
5465773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5466773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
5467c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5468c2248fc9SDouglas Gilbert 		goto check_cond;
5469c2248fc9SDouglas Gilbert 	}
5470f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
5471c2248fc9SDouglas Gilbert 		u8 rem;
5472c2248fc9SDouglas Gilbert 		int j;
5473c2248fc9SDouglas Gilbert 
5474c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5475c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
5476c2248fc9SDouglas Gilbert 			if (rem) {
5477c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
5478c2248fc9SDouglas Gilbert 					if (0x80 & rem)
5479c2248fc9SDouglas Gilbert 						break;
5480c2248fc9SDouglas Gilbert 				}
5481c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5482c2248fc9SDouglas Gilbert 				goto check_cond;
5483c2248fc9SDouglas Gilbert 			}
5484c2248fc9SDouglas Gilbert 		}
5485c2248fc9SDouglas Gilbert 	}
5486f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
5487b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
5488b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
5489f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
5490c2248fc9SDouglas Gilbert 		if (errsts)
5491c2248fc9SDouglas Gilbert 			goto check_cond;
5492c2248fc9SDouglas Gilbert 	}
5493c4837394SDouglas Gilbert 	if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
5494c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
5495773642d9SDouglas Gilbert 		if (sdebug_verbose)
5496c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5497c2248fc9SDouglas Gilbert 				    "%s\n", my_name, "initializing command "
5498c2248fc9SDouglas Gilbert 				    "required");
5499c2248fc9SDouglas Gilbert 		errsts = check_condition_result;
5500c2248fc9SDouglas Gilbert 		goto fini;
5501c2248fc9SDouglas Gilbert 	}
5502773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
5503c2248fc9SDouglas Gilbert 		goto fini;
5504f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
5505c4837394SDouglas Gilbert 		if (fake_timeout(scp))
5506c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
5507c2248fc9SDouglas Gilbert 	}
5508f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
5509f46eb0e9SDouglas Gilbert 		errsts = oip->pfp(scp, devip);	/* calls a resp_* function */
5510c2248fc9SDouglas Gilbert 	else if (r_pfp)	/* if leaf function ptr NULL, try the root's */
5511c2248fc9SDouglas Gilbert 		errsts = r_pfp(scp, devip);
5512c2248fc9SDouglas Gilbert 
5513c2248fc9SDouglas Gilbert fini:
5514c2248fc9SDouglas Gilbert 	return schedule_resp(scp, devip, errsts,
5515c2206098SDouglas Gilbert 			     ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay));
5516c2248fc9SDouglas Gilbert check_cond:
5517c2248fc9SDouglas Gilbert 	return schedule_resp(scp, devip, check_condition_result, 0);
5518f46eb0e9SDouglas Gilbert err_out:
5519f46eb0e9SDouglas Gilbert 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0);
5520c2248fc9SDouglas Gilbert }
5521c2248fc9SDouglas Gilbert 
55229e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
5523c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
5524c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
55259e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
55269e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
55279e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
55289e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
55299e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
55309e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
55319e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
5532185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
5533cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
55349e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
55359e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
5536cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
5537cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
55389e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
5539c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
55409e603ca0SFUJITA Tomonori 	.this_id =		7,
554165e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
5542cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
55436bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
55449e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
55459e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
5546c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
55479e603ca0SFUJITA Tomonori };
55489e603ca0SFUJITA Tomonori 
55491da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev)
55501da177e4SLinus Torvalds {
55511da177e4SLinus Torvalds 	int error = 0;
55521da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
55531da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
5554f46eb0e9SDouglas Gilbert 	int hprot;
55551da177e4SLinus Torvalds 
55561da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
55571da177e4SLinus Torvalds 
5558773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
5559773642d9SDouglas Gilbert 	if (sdebug_clustering)
55600759c666SAkinobu Mita 		sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
55611da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
55621da177e4SLinus Torvalds 	if (NULL == hpnt) {
5563c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
55641da177e4SLinus Torvalds 		error = -ENODEV;
55651da177e4SLinus Torvalds 		return error;
55661da177e4SLinus Torvalds 	}
5567c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
55689b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
5569c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
5570c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
5571c4837394SDouglas Gilbert 	}
5572c4837394SDouglas Gilbert 	/* Decide whether to tell scsi subsystem that we want mq */
5573c4837394SDouglas Gilbert 	/* Following should give the same answer for each host */
5574c4837394SDouglas Gilbert 	sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1);
5575c4837394SDouglas Gilbert 	if (sdebug_mq_active)
5576c4837394SDouglas Gilbert 		hpnt->nr_hw_queues = submit_queues;
55771da177e4SLinus Torvalds 
55781da177e4SLinus Torvalds         sdbg_host->shost = hpnt;
55791da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
5580773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5581773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
55821da177e4SLinus Torvalds 	else
5583773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
5584773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
5585f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
55861da177e4SLinus Torvalds 
5587f46eb0e9SDouglas Gilbert 	hprot = 0;
5588c6a44287SMartin K. Petersen 
5589773642d9SDouglas Gilbert 	switch (sdebug_dif) {
5590c6a44287SMartin K. Petersen 
55918475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
5592f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
5593773642d9SDouglas Gilbert 		if (sdebug_dix)
5594f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
5595c6a44287SMartin K. Petersen 		break;
5596c6a44287SMartin K. Petersen 
55978475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
5598f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
5599773642d9SDouglas Gilbert 		if (sdebug_dix)
5600f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
5601c6a44287SMartin K. Petersen 		break;
5602c6a44287SMartin K. Petersen 
56038475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
5604f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
5605773642d9SDouglas Gilbert 		if (sdebug_dix)
5606f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
5607c6a44287SMartin K. Petersen 		break;
5608c6a44287SMartin K. Petersen 
5609c6a44287SMartin K. Petersen 	default:
5610773642d9SDouglas Gilbert 		if (sdebug_dix)
5611f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
5612c6a44287SMartin K. Petersen 		break;
5613c6a44287SMartin K. Petersen 	}
5614c6a44287SMartin K. Petersen 
5615f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
5616c6a44287SMartin K. Petersen 
5617f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
5618c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
5619f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5620f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5621f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5622f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5623f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5624f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5625f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
5626c6a44287SMartin K. Petersen 
5627773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
5628c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5629c6a44287SMartin K. Petersen 	else
5630c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5631c6a44287SMartin K. Petersen 
5632773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5633773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
5634c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
5635c4837394SDouglas Gilbert 		sdebug_statistics = true;
56361da177e4SLinus Torvalds         error = scsi_add_host(hpnt, &sdbg_host->dev);
56371da177e4SLinus Torvalds         if (error) {
5638c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
56391da177e4SLinus Torvalds                 error = -ENODEV;
56401da177e4SLinus Torvalds 		scsi_host_put(hpnt);
56411da177e4SLinus Torvalds         } else
56421da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
56431da177e4SLinus Torvalds 
56441da177e4SLinus Torvalds 	return error;
56451da177e4SLinus Torvalds }
56461da177e4SLinus Torvalds 
56471da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev)
56481da177e4SLinus Torvalds {
56491da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
56508b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
56511da177e4SLinus Torvalds 
56521da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
56531da177e4SLinus Torvalds 
56541da177e4SLinus Torvalds 	if (!sdbg_host) {
5655c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
56561da177e4SLinus Torvalds 		return -ENODEV;
56571da177e4SLinus Torvalds 	}
56581da177e4SLinus Torvalds 
56591da177e4SLinus Torvalds         scsi_remove_host(sdbg_host->shost);
56601da177e4SLinus Torvalds 
56618b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
56628b40228fSFUJITA Tomonori 				 dev_list) {
56631da177e4SLinus Torvalds                 list_del(&sdbg_devinfo->dev_list);
56641da177e4SLinus Torvalds                 kfree(sdbg_devinfo);
56651da177e4SLinus Torvalds         }
56661da177e4SLinus Torvalds 
56671da177e4SLinus Torvalds         scsi_host_put(sdbg_host->shost);
56681da177e4SLinus Torvalds         return 0;
56691da177e4SLinus Torvalds }
56701da177e4SLinus Torvalds 
56718dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
56728dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
56731da177e4SLinus Torvalds {
56748dea0d02SFUJITA Tomonori 	return 1;
56758dea0d02SFUJITA Tomonori }
56761da177e4SLinus Torvalds 
56778dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
56788dea0d02SFUJITA Tomonori 	.name = "pseudo",
56798dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
56808dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
56818dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
568282069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
56838dea0d02SFUJITA Tomonori };
5684