xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision f46eb0e9)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
31da177e4SLinus Torvalds  *  Copyright (C) 1992  Eric Youngdale
41da177e4SLinus Torvalds  *  Simulate a host adapter with 2 disks attached.  Do a lot of checking
51da177e4SLinus Torvalds  *  to make sure that we are not getting blocks mixed up, and PANIC if
61da177e4SLinus Torvalds  *  anything out of the ordinary is seen.
71da177e4SLinus Torvalds  * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
81da177e4SLinus Torvalds  *
9773642d9SDouglas Gilbert  * Copyright (C) 2001 - 2016 Douglas Gilbert
101da177e4SLinus Torvalds  *
11773642d9SDouglas Gilbert  * This program is free software; you can redistribute it and/or modify
12773642d9SDouglas Gilbert  * it under the terms of the GNU General Public License as published by
13773642d9SDouglas Gilbert  * the Free Software Foundation; either version 2, or (at your option)
14773642d9SDouglas Gilbert  * any later version.
151da177e4SLinus Torvalds  *
1678d4e5a0SDouglas Gilbert  *  For documentation see http://sg.danny.cz/sg/sdebug26.html
171da177e4SLinus Torvalds  *
181da177e4SLinus Torvalds  */
191da177e4SLinus Torvalds 
20c1287970STomas Winkler 
21c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
22c1287970STomas Winkler 
231da177e4SLinus Torvalds #include <linux/module.h>
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds #include <linux/kernel.h>
261da177e4SLinus Torvalds #include <linux/errno.h>
27b333a819SDouglas Gilbert #include <linux/jiffies.h>
285a0e3ad6STejun Heo #include <linux/slab.h>
291da177e4SLinus Torvalds #include <linux/types.h>
301da177e4SLinus Torvalds #include <linux/string.h>
311da177e4SLinus Torvalds #include <linux/genhd.h>
321da177e4SLinus Torvalds #include <linux/fs.h>
331da177e4SLinus Torvalds #include <linux/init.h>
341da177e4SLinus Torvalds #include <linux/proc_fs.h>
351da177e4SLinus Torvalds #include <linux/vmalloc.h>
361da177e4SLinus Torvalds #include <linux/moduleparam.h>
37852e034dSJens Axboe #include <linux/scatterlist.h>
381da177e4SLinus Torvalds #include <linux/blkdev.h>
39c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h>
40cbf67842SDouglas Gilbert #include <linux/spinlock.h>
41cbf67842SDouglas Gilbert #include <linux/interrupt.h>
42cbf67842SDouglas Gilbert #include <linux/atomic.h>
43cbf67842SDouglas Gilbert #include <linux/hrtimer.h>
44c6a44287SMartin K. Petersen 
45c6a44287SMartin K. Petersen #include <net/checksum.h>
469ff26eefSFUJITA Tomonori 
4744d92694SMartin K. Petersen #include <asm/unaligned.h>
4844d92694SMartin K. Petersen 
499ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
509ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
519ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
521da177e4SLinus Torvalds #include <scsi/scsi_host.h>
531da177e4SLinus Torvalds #include <scsi/scsicam.h>
54a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
55cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h>
56395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
571da177e4SLinus Torvalds 
58c6a44287SMartin K. Petersen #include "sd.h"
591da177e4SLinus Torvalds #include "scsi_logging.h"
601da177e4SLinus Torvalds 
61773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */
62773642d9SDouglas Gilbert #define SCSI_DEBUG_VERSION "1.86"
63773642d9SDouglas Gilbert static const char *sdebug_version_date = "20160422";
64cbf67842SDouglas Gilbert 
65cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
661da177e4SLinus Torvalds 
676f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
68c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
69c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
70c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
711da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
72c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
731da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7422017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
751da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
76c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
77cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
78cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
7919c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
8019c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8122017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8222017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
83cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
84cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
85cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
8622017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9
871da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
886f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
89c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
90c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
9122017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d
92acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1	/* with TARGET_CHANGED_ASC */
93acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
941da177e4SLinus Torvalds 
956f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
966f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
976f3cbf55SDouglas Gilbert 
981da177e4SLinus Torvalds /* Default values for driver parameters */
991da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1001da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1011da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1021da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1031da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1041da177e4SLinus Torvalds  */
1055b94e232SMartin K. Petersen #define DEF_ATO 1
106c2206098SDouglas Gilbert #define DEF_JDELAY   1		/* if > 0 unit is a jiffy */
1071da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1085b94e232SMartin K. Petersen #define DEF_DIF 0
1095b94e232SMartin K. Petersen #define DEF_DIX 0
1105b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1111da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1125b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1135b94e232SMartin K. Petersen #define DEF_GUARD 0
114cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1155b94e232SMartin K. Petersen #define DEF_LBPU 0
1165b94e232SMartin K. Petersen #define DEF_LBPWS 0
1175b94e232SMartin K. Petersen #define DEF_LBPWS10 0
118be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1195b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
120cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1215b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1221da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1231da177e4SLinus Torvalds #define DEF_OPTS   0
12432c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1255b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
1265b94e232SMartin K. Petersen #define DEF_PTYPE   0
127d986788bSMartin Pitt #define DEF_REMOVABLE false
128e46b0344SDouglas Gilbert #define DEF_SCSI_LEVEL   6    /* INQUIRY, byte2 [6->SPC-4] */
1295b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1305b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1315b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1326014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1336014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1345b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1355b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1365b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
137c2248fc9SDouglas Gilbert #define DEF_STRICT 0
138c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999
1391da177e4SLinus Torvalds 
140773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
141773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
142773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
143773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
144773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
145773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
146773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
147773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
148773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
149773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
150773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
151773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF		0x400
152773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF		0x800
153773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE		0x1000
154773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE		0x2000
155773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE		0x4000
156773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
157773642d9SDouglas Gilbert 			      SDEBUG_OPT_RESET_NOISE)
158773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
159773642d9SDouglas Gilbert 				  SDEBUG_OPT_TRANSPORT_ERR | \
160773642d9SDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
161773642d9SDouglas Gilbert 				  SDEBUG_OPT_SHORT_TRANSFER)
1621da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
163fd32119bSDouglas Gilbert  *   - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
1641da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
165773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_RECOVERED_ERR is set.
1666f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
167773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_TRANSPORT_ERR is set.
1681da177e4SLinus Torvalds  *
1691da177e4SLinus Torvalds  * When "every_nth" < 0 then after "- every_nth" commands:
170fd32119bSDouglas Gilbert  *   - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
1711da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
172773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_RECOVERED_ERR is set.
1736f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
174773642d9SDouglas Gilbert  *     commands if _DEBUG_OPT_TRANSPORT_ERR is set.
175773642d9SDouglas Gilbert  * This will continue on every subsequent command until some other action
176773642d9SDouglas Gilbert  * occurs (e.g. the user * writing a new value (other than -1 or 1) to
177773642d9SDouglas Gilbert  * every_nth via sysfs).
1781da177e4SLinus Torvalds  */
1791da177e4SLinus Torvalds 
180cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
181cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
182cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
183cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
184cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
185cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1
186cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2
1870d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3
18819c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4
189acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5	/* simulate firmware change */
190acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
191acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7
192cbf67842SDouglas Gilbert 
193773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
1941da177e4SLinus Torvalds  * sector on read commands: */
1951da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
19632f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
1971da177e4SLinus Torvalds 
1981da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
1991da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
2001da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
2011da177e4SLinus Torvalds 
202cbf67842SDouglas Gilbert /* SCSI_DEBUG_CANQUEUE is the maximum number of commands that can be queued
203cbf67842SDouglas Gilbert  * (for response) at one time. Can be reduced by max_queue option. Command
204c2206098SDouglas Gilbert  * responses are not queued when jdelay=0 and ndelay=0. The per-device
205cbf67842SDouglas Gilbert  * DEF_CMD_PER_LUN can be changed via sysfs:
206cbf67842SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth but cannot exceed
207cbf67842SDouglas Gilbert  * SCSI_DEBUG_CANQUEUE. */
208cbf67842SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE_WORDS  9	/* a WORD is bits in a long */
209cbf67842SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE  (SCSI_DEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
210cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN  255
211cbf67842SDouglas Gilbert 
212cbf67842SDouglas Gilbert #if DEF_CMD_PER_LUN > SCSI_DEBUG_CANQUEUE
213cbf67842SDouglas Gilbert #warning "Expect DEF_CMD_PER_LUN <= SCSI_DEBUG_CANQUEUE"
214cbf67842SDouglas Gilbert #endif
21578d4e5a0SDouglas Gilbert 
216fd32119bSDouglas Gilbert #define F_D_IN			1
217fd32119bSDouglas Gilbert #define F_D_OUT			2
218fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
219fd32119bSDouglas Gilbert #define F_D_UNKN		8
220fd32119bSDouglas Gilbert #define F_RL_WLUN_OK		0x10
221fd32119bSDouglas Gilbert #define F_SKIP_UA		0x20
222fd32119bSDouglas Gilbert #define F_DELAY_OVERR		0x40
223fd32119bSDouglas Gilbert #define F_SA_LOW		0x80	/* cdb byte 1, bits 4 to 0 */
224fd32119bSDouglas Gilbert #define F_SA_HIGH		0x100	/* as used by variable length cdbs */
225fd32119bSDouglas Gilbert #define F_INV_OP		0x200
226fd32119bSDouglas Gilbert #define F_FAKE_RW		0x400
227fd32119bSDouglas Gilbert #define F_M_ACCESS		0x800	/* media access */
228fd32119bSDouglas Gilbert 
229fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
230fd32119bSDouglas Gilbert #define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW)
231fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
232fd32119bSDouglas Gilbert 
233fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4
234fd32119bSDouglas Gilbert 
235fd32119bSDouglas Gilbert #define SCSI_DEBUG_MAX_CMD_LEN 32
236fd32119bSDouglas Gilbert 
237fd32119bSDouglas Gilbert 
238fd32119bSDouglas Gilbert struct sdebug_dev_info {
239fd32119bSDouglas Gilbert 	struct list_head dev_list;
240fd32119bSDouglas Gilbert 	unsigned int channel;
241fd32119bSDouglas Gilbert 	unsigned int target;
242fd32119bSDouglas Gilbert 	u64 lun;
243fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
244fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
245fd32119bSDouglas Gilbert 	atomic_t num_in_q;
246fd32119bSDouglas Gilbert 	char stopped;		/* TODO: should be atomic */
247fd32119bSDouglas Gilbert 	bool used;
248fd32119bSDouglas Gilbert };
249fd32119bSDouglas Gilbert 
250fd32119bSDouglas Gilbert struct sdebug_host_info {
251fd32119bSDouglas Gilbert 	struct list_head host_list;
252fd32119bSDouglas Gilbert 	struct Scsi_Host *shost;
253fd32119bSDouglas Gilbert 	struct device dev;
254fd32119bSDouglas Gilbert 	struct list_head dev_info_list;
255fd32119bSDouglas Gilbert };
256fd32119bSDouglas Gilbert 
257fd32119bSDouglas Gilbert #define to_sdebug_host(d)	\
258fd32119bSDouglas Gilbert 	container_of(d, struct sdebug_host_info, dev)
259fd32119bSDouglas Gilbert 
260fd32119bSDouglas Gilbert struct sdebug_defer {
261fd32119bSDouglas Gilbert 	struct hrtimer hrt;
262fd32119bSDouglas Gilbert 	struct execute_work ew;
263fd32119bSDouglas Gilbert 	int qa_indx;
264fd32119bSDouglas Gilbert };
265fd32119bSDouglas Gilbert 
266fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
267fd32119bSDouglas Gilbert 	/* in_use flagged by a bit in queued_in_use_bm[] */
268fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
269fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
270fd32119bSDouglas Gilbert };
271fd32119bSDouglas Gilbert 
272fd32119bSDouglas Gilbert struct sdebug_scmd_extra_t {
273fd32119bSDouglas Gilbert 	bool inj_recovered;
274fd32119bSDouglas Gilbert 	bool inj_transport;
275fd32119bSDouglas Gilbert 	bool inj_dif;
276fd32119bSDouglas Gilbert 	bool inj_dix;
277fd32119bSDouglas Gilbert 	bool inj_short;
278fd32119bSDouglas Gilbert };
279fd32119bSDouglas Gilbert 
280fd32119bSDouglas Gilbert struct opcode_info_t {
281fd32119bSDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff
282fd32119bSDouglas Gilbert 				 * for terminating element */
283fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
284fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
285fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
286fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
287fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
288fd32119bSDouglas Gilbert 	u8 len_mask[16];	/* len=len_mask[0], then mask for cdb[1]... */
289fd32119bSDouglas Gilbert 				/* ignore cdb bytes after position 15 */
290fd32119bSDouglas Gilbert };
291fd32119bSDouglas Gilbert 
292fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
293c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
294c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
295c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
296c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
297c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
298c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
299c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
300c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
301c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
302c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
303c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
304c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
305c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
306c2248fc9SDouglas Gilbert 	SDEB_I_SERV_ACT_IN = 12,	/* 12, 16 */
307c2248fc9SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT = 13,	/* 12, 16 */
308c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
309c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
310c2248fc9SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* 10 only */
311c2248fc9SDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,
312c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
313c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
314c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
315c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
316c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
317c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
318c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
319c2248fc9SDouglas Gilbert 	SDEB_I_XDWRITEREAD = 25,	/* 10 only */
320c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_BUFFER = 26,
321c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_SAME = 27,		/* 10, 16 */
322c2248fc9SDouglas Gilbert 	SDEB_I_SYNC_CACHE = 28,		/* 10 only */
323c2248fc9SDouglas Gilbert 	SDEB_I_COMP_WRITE = 29,
324c2248fc9SDouglas Gilbert 	SDEB_I_LAST_ELEMENT = 30,	/* keep this last */
325c2248fc9SDouglas Gilbert };
326c2248fc9SDouglas Gilbert 
327c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
328c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
329c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
330c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
331c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
332c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
333c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
334c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
335c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
336c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
337c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
338c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
339c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
340c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
341c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
342c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
343c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
344c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
345c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
346c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
347fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
348c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
349c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
350c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
351c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
352c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
353c2248fc9SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
354c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
355c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT,
356c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
357c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
358c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
359c2248fc9SDouglas Gilbert 	SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN,
360c2248fc9SDouglas Gilbert 	     0, 0, 0, 0,
361c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
362c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
363c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
364c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
365c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
366c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
367c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
368c2248fc9SDouglas Gilbert };
369c2248fc9SDouglas Gilbert 
370c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
371c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
372c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
373c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
374c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
375c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
376c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
377c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
378c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
379c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
380c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
381c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
382c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
383c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
38438d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
38538d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
386c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
387c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
388c2248fc9SDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
38938d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
390acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
391c2248fc9SDouglas Gilbert 
392c2248fc9SDouglas Gilbert static const struct opcode_info_t msense_iarr[1] = {
393c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
394c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
395c2248fc9SDouglas Gilbert };
396c2248fc9SDouglas Gilbert 
397c2248fc9SDouglas Gilbert static const struct opcode_info_t mselect_iarr[1] = {
398c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
399c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
400c2248fc9SDouglas Gilbert };
401c2248fc9SDouglas Gilbert 
402c2248fc9SDouglas Gilbert static const struct opcode_info_t read_iarr[3] = {
403c2248fc9SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */
404c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
405c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
406c2248fc9SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */
407c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
408c2248fc9SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */
409c2248fc9SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
410c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
411c2248fc9SDouglas Gilbert };
412c2248fc9SDouglas Gilbert 
413c2248fc9SDouglas Gilbert static const struct opcode_info_t write_iarr[3] = {
414c2248fc9SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,   /* 10 */
415c2248fc9SDouglas Gilbert 	    {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
416c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
417c2248fc9SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,    /* 6 */
418c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
419c2248fc9SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,   /* 12 */
420c2248fc9SDouglas Gilbert 	    {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
421c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
422c2248fc9SDouglas Gilbert };
423c2248fc9SDouglas Gilbert 
424c2248fc9SDouglas Gilbert static const struct opcode_info_t sa_in_iarr[1] = {
425c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
426c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
427c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },
428c2248fc9SDouglas Gilbert };
429c2248fc9SDouglas Gilbert 
430c2248fc9SDouglas Gilbert static const struct opcode_info_t vl_iarr[1] = {	/* VARIABLE LENGTH */
431c2248fc9SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0,
432c2248fc9SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa,
433c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
434c2248fc9SDouglas Gilbert };
435c2248fc9SDouglas Gilbert 
436c2248fc9SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[2] = {
43738d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
438c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
439c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
44038d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
441c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
442c2248fc9SDouglas Gilbert 	     0, 0} },
443c2248fc9SDouglas Gilbert };
444c2248fc9SDouglas Gilbert 
445c2248fc9SDouglas Gilbert static const struct opcode_info_t write_same_iarr[1] = {
446c2248fc9SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL,
447c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
448c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x1f, 0xc7} },
449c2248fc9SDouglas Gilbert };
450c2248fc9SDouglas Gilbert 
451c2248fc9SDouglas Gilbert static const struct opcode_info_t reserve_iarr[1] = {
452c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,	/* RESERVE(6) */
453c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
454c2248fc9SDouglas Gilbert };
455c2248fc9SDouglas Gilbert 
456c2248fc9SDouglas Gilbert static const struct opcode_info_t release_iarr[1] = {
457c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,	/* RELEASE(6) */
458c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
459c2248fc9SDouglas Gilbert };
460c2248fc9SDouglas Gilbert 
461c2248fc9SDouglas Gilbert 
462c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
463c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
464c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
465c2248fc9SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
466c2248fc9SDouglas Gilbert /* 0 */
467c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,
468c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
469c2248fc9SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL,
470c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
471c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
472c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
473c2248fc9SDouglas Gilbert 	     0, 0} },
474c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
475c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
476c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
477c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
478c2248fc9SDouglas Gilbert 	{1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr,
479c2248fc9SDouglas Gilbert 	    {10,  0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
480c2248fc9SDouglas Gilbert 	     0} },
481c2248fc9SDouglas Gilbert 	{1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr,
482c2248fc9SDouglas Gilbert 	    {10,  0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
483c2248fc9SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,
484c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
485c2248fc9SDouglas Gilbert 	     0, 0, 0} },
486c2248fc9SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,
487c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
488c2248fc9SDouglas Gilbert 	     0, 0} },
489c2248fc9SDouglas Gilbert 	{3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr,
490c2248fc9SDouglas Gilbert 	    {16,  0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
491c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x9f, 0xc7} },		/* READ(16) */
492c2248fc9SDouglas Gilbert /* 10 */
493c2248fc9SDouglas Gilbert 	{3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr,
494c2248fc9SDouglas Gilbert 	    {16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
495c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x9f, 0xc7} },		/* WRITE(16) */
496c2248fc9SDouglas Gilbert 	{0, 0x1b, 0, 0, resp_start_stop, NULL,		/* START STOP UNIT */
497c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
498c2248fc9SDouglas Gilbert 	{1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr,
499c2248fc9SDouglas Gilbert 	    {16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
500c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x1, 0xc7} },	/* READ CAPACITY(16) */
501c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */
502c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
503c2248fc9SDouglas Gilbert 	{2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr,
504c2248fc9SDouglas Gilbert 	    {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0,
505c2248fc9SDouglas Gilbert 	     0} },
506c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
507c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
508f7f9f26bSDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */
509f7f9f26bSDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
510f7f9f26bSDouglas Gilbert 	     0, 0, 0, 0, 0, 0} },
511c2248fc9SDouglas Gilbert 	{1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0,
512c2248fc9SDouglas Gilbert 	    vl_iarr, {32,  0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0,
513c2248fc9SDouglas Gilbert 		      0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */
514c2248fc9SDouglas Gilbert 	{1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */
515c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
516c2248fc9SDouglas Gilbert 	     0} },
517c2248fc9SDouglas Gilbert 	{1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */
518c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
519c2248fc9SDouglas Gilbert 	     0} },
520c2248fc9SDouglas Gilbert /* 20 */
521f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
522f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
523c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
524c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
525c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
526c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
527c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
528c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
529c2248fc9SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */
530c2248fc9SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
531c2248fc9SDouglas Gilbert 	{0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10,
532c2248fc9SDouglas Gilbert 	    NULL, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7,
533c2248fc9SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
534acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
535acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
536acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
537c2248fc9SDouglas Gilbert 	{1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10,
538c2248fc9SDouglas Gilbert 	    write_same_iarr, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff,
539c2248fc9SDouglas Gilbert 			      0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
540c2248fc9SDouglas Gilbert 	{0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */
541c2248fc9SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
542c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
54338d5c833SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL,
544c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
545c2248fc9SDouglas Gilbert 	     0, 0xff, 0x1f, 0xc7} },		/* COMPARE AND WRITE */
546c2248fc9SDouglas Gilbert 
547c2248fc9SDouglas Gilbert /* 30 */
548c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
549c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
550c2248fc9SDouglas Gilbert };
551c2248fc9SDouglas Gilbert 
552773642d9SDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;
553773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
554c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
555773642d9SDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
556773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
557773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
558773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
559773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
560773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
561773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
562773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
563773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
564773642d9SDouglas Gilbert static int sdebug_max_queue = SCSI_DEBUG_CANQUEUE;
565cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
566c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
567773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
568773642d9SDouglas Gilbert static int sdebug_no_uld;
569773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
570773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
571773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
572773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
573773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
574773642d9SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
575773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
576773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
577773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
578773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
579773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
580773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
581773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
582773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
583773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
584773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
585773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
586773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
587773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
588773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
589773642d9SDouglas Gilbert static bool sdebug_clustering;
590773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
591773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
592817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
593773642d9SDouglas Gilbert static bool sdebug_verbose;
594f46eb0e9SDouglas Gilbert static bool have_dif_prot;
5951da177e4SLinus Torvalds 
596cbf67842SDouglas Gilbert static atomic_t sdebug_cmnd_count;
597cbf67842SDouglas Gilbert static atomic_t sdebug_completions;
598cbf67842SDouglas Gilbert static atomic_t sdebug_a_tsf;		/* counter of 'almost' TSFs */
5991da177e4SLinus Torvalds 
600c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
6011da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
6021da177e4SLinus Torvalds 
6031da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
6041da177e4SLinus Torvalds    may still need them */
6051da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
6061da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
6071da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
6081da177e4SLinus Torvalds 
6091da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
6101da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
6111da177e4SLinus Torvalds 
6121da177e4SLinus Torvalds static unsigned char *fake_storep;	/* ramdisk storage */
613e18d8beaSAkinobu Mita static struct sd_dif_tuple *dif_storep;	/* protection info */
61444d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
6151da177e4SLinus Torvalds 
61644d92694SMartin K. Petersen static unsigned long map_size;
617cbf67842SDouglas Gilbert static int num_aborts;
618cbf67842SDouglas Gilbert static int num_dev_resets;
619cbf67842SDouglas Gilbert static int num_target_resets;
620cbf67842SDouglas Gilbert static int num_bus_resets;
621cbf67842SDouglas Gilbert static int num_host_resets;
622c6a44287SMartin K. Petersen static int dix_writes;
623c6a44287SMartin K. Petersen static int dix_reads;
624c6a44287SMartin K. Petersen static int dif_errors;
6251da177e4SLinus Torvalds 
626fd32119bSDouglas Gilbert static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
627fd32119bSDouglas Gilbert static unsigned long queued_in_use_bm[SCSI_DEBUG_CANQUEUE_WORDS];
628fd32119bSDouglas Gilbert 
6291da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock);
6301da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
6311da177e4SLinus Torvalds 
632cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
633cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
6341da177e4SLinus Torvalds 
6351da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
6361da177e4SLinus Torvalds 
6371da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
6381da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
6391da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
6401da177e4SLinus Torvalds };
6411da177e4SLinus Torvalds 
6421da177e4SLinus Torvalds static const int check_condition_result =
6431da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
6441da177e4SLinus Torvalds 
645c6a44287SMartin K. Petersen static const int illegal_condition_result =
646c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
647c6a44287SMartin K. Petersen 
648cbf67842SDouglas Gilbert static const int device_qfull_result =
649cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
650cbf67842SDouglas Gilbert 
651fd32119bSDouglas Gilbert 
652fd32119bSDouglas Gilbert static unsigned int scsi_debug_lbp(void)
653fd32119bSDouglas Gilbert {
654fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
655fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
656fd32119bSDouglas Gilbert }
657c65b1445SDouglas Gilbert 
65814faa944SAkinobu Mita static void *fake_store(unsigned long long lba)
65914faa944SAkinobu Mita {
66014faa944SAkinobu Mita 	lba = do_div(lba, sdebug_store_sectors);
66114faa944SAkinobu Mita 
662773642d9SDouglas Gilbert 	return fake_storep + lba * sdebug_sector_size;
66314faa944SAkinobu Mita }
66414faa944SAkinobu Mita 
66514faa944SAkinobu Mita static struct sd_dif_tuple *dif_store(sector_t sector)
66614faa944SAkinobu Mita {
66749413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
66814faa944SAkinobu Mita 
66914faa944SAkinobu Mita 	return dif_storep + sector;
67014faa944SAkinobu Mita }
67114faa944SAkinobu Mita 
6728dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
6738dea0d02SFUJITA Tomonori {
6748dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
6758dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
6768dea0d02SFUJITA Tomonori 
6778dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
6788dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
6798dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
6808dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
681773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
682773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
6838dea0d02SFUJITA Tomonori 		else
684773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
685773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
686f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
6878dea0d02SFUJITA Tomonori 	}
6888dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
6898dea0d02SFUJITA Tomonori }
6908dea0d02SFUJITA Tomonori 
69122017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
69222017ed2SDouglas Gilbert 
69322017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
694fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
695fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
69622017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
69722017ed2SDouglas Gilbert {
69822017ed2SDouglas Gilbert 	unsigned char *sbuff;
69922017ed2SDouglas Gilbert 	u8 sks[4];
70022017ed2SDouglas Gilbert 	int sl, asc;
70122017ed2SDouglas Gilbert 
70222017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
70322017ed2SDouglas Gilbert 	if (!sbuff) {
70422017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
70522017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
70622017ed2SDouglas Gilbert 		return;
70722017ed2SDouglas Gilbert 	}
70822017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
70922017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
710773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
71122017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
71222017ed2SDouglas Gilbert 	sks[0] = 0x80;
71322017ed2SDouglas Gilbert 	if (c_d)
71422017ed2SDouglas Gilbert 		sks[0] |= 0x40;
71522017ed2SDouglas Gilbert 	if (in_bit >= 0) {
71622017ed2SDouglas Gilbert 		sks[0] |= 0x8;
71722017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
71822017ed2SDouglas Gilbert 	}
71922017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
720773642d9SDouglas Gilbert 	if (sdebug_dsense) {
72122017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
72222017ed2SDouglas Gilbert 		sbuff[7] = sl;
72322017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
72422017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
72522017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
72622017ed2SDouglas Gilbert 	} else
72722017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
728773642d9SDouglas Gilbert 	if (sdebug_verbose)
72922017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
73022017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
73122017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
73222017ed2SDouglas Gilbert }
73322017ed2SDouglas Gilbert 
734cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
7358dea0d02SFUJITA Tomonori {
7368dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
7378dea0d02SFUJITA Tomonori 
738cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
739cbf67842SDouglas Gilbert 	if (!sbuff) {
740cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
741cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
742cbf67842SDouglas Gilbert 		return;
743cbf67842SDouglas Gilbert 	}
744cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
7458dea0d02SFUJITA Tomonori 
746773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
7478dea0d02SFUJITA Tomonori 
748773642d9SDouglas Gilbert 	if (sdebug_verbose)
749cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
750cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
751cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
7528dea0d02SFUJITA Tomonori }
7531da177e4SLinus Torvalds 
754fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
75522017ed2SDouglas Gilbert {
75622017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
75722017ed2SDouglas Gilbert }
75822017ed2SDouglas Gilbert 
7591da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
7601da177e4SLinus Torvalds {
761773642d9SDouglas Gilbert 	if (sdebug_verbose) {
762cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
763cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
764cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
765cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
766cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
767cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
768cbf67842SDouglas Gilbert 				    __func__);
769cbf67842SDouglas Gilbert 		else
770cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
771cbf67842SDouglas Gilbert 				    __func__, cmd);
7721da177e4SLinus Torvalds 	}
7731da177e4SLinus Torvalds 	return -EINVAL;
7741da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
7751da177e4SLinus Torvalds }
7761da177e4SLinus Torvalds 
77719c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
77819c8ead7SEwan D. Milne {
77919c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
78019c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
78119c8ead7SEwan D. Milne 
78219c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
78319c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
78419c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
78519c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
78619c8ead7SEwan D. Milne 			    (devip->target == dp->target))
78719c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
78819c8ead7SEwan D. Milne 		}
78919c8ead7SEwan D. Milne 	}
79019c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
79119c8ead7SEwan D. Milne }
79219c8ead7SEwan D. Milne 
793f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
7941da177e4SLinus Torvalds {
795cbf67842SDouglas Gilbert 	int k;
796cbf67842SDouglas Gilbert 
797cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
798cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
799cbf67842SDouglas Gilbert 		const char *cp = NULL;
800cbf67842SDouglas Gilbert 
801cbf67842SDouglas Gilbert 		switch (k) {
802cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
803f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
804f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
805773642d9SDouglas Gilbert 			if (sdebug_verbose)
806cbf67842SDouglas Gilbert 				cp = "power on reset";
807cbf67842SDouglas Gilbert 			break;
808cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
809f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
810f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
811773642d9SDouglas Gilbert 			if (sdebug_verbose)
812cbf67842SDouglas Gilbert 				cp = "bus reset";
813cbf67842SDouglas Gilbert 			break;
814cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
815f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
816f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
817773642d9SDouglas Gilbert 			if (sdebug_verbose)
818cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
819cbf67842SDouglas Gilbert 			break;
8200d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
821f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
822f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
823773642d9SDouglas Gilbert 			if (sdebug_verbose)
8240d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
825f49accf1SEwan D. Milne 			break;
826acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
827f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
828acafd0b9SEwan D. Milne 				TARGET_CHANGED_ASC, MICROCODE_CHANGED_ASCQ);
829773642d9SDouglas Gilbert 			if (sdebug_verbose)
830acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
831acafd0b9SEwan D. Milne 			break;
832acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
833f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
834acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
835acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
836773642d9SDouglas Gilbert 			if (sdebug_verbose)
837acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
838acafd0b9SEwan D. Milne 			break;
83919c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
84019c8ead7SEwan D. Milne 			/*
84119c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
84219c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
84319c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
84419c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
845773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
84619c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
84719c8ead7SEwan D. Milne 			 */
848773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
84919c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
850f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
85119c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
85219c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
853773642d9SDouglas Gilbert 			if (sdebug_verbose)
85419c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
85519c8ead7SEwan D. Milne 			break;
856cbf67842SDouglas Gilbert 		default:
857773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
858773642d9SDouglas Gilbert 			if (sdebug_verbose)
859cbf67842SDouglas Gilbert 				cp = "unknown";
860cbf67842SDouglas Gilbert 			break;
861cbf67842SDouglas Gilbert 		}
862cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
863773642d9SDouglas Gilbert 		if (sdebug_verbose)
864f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
865cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
866cbf67842SDouglas Gilbert 				   my_name, cp);
8671da177e4SLinus Torvalds 		return check_condition_result;
8681da177e4SLinus Torvalds 	}
8691da177e4SLinus Torvalds 	return 0;
8701da177e4SLinus Torvalds }
8711da177e4SLinus Torvalds 
8721da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
8731da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
8741da177e4SLinus Torvalds 				int arr_len)
8751da177e4SLinus Torvalds {
87621a61829SFUJITA Tomonori 	int act_len;
877072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
8781da177e4SLinus Torvalds 
879072d0bb3SFUJITA Tomonori 	if (!sdb->length)
8801da177e4SLinus Torvalds 		return 0;
881072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
882773642d9SDouglas Gilbert 		return DID_ERROR << 16;
88321a61829SFUJITA Tomonori 
88421a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
88521a61829SFUJITA Tomonori 				      arr, arr_len);
88621a61829SFUJITA Tomonori 	sdb->resid = scsi_bufflen(scp) - act_len;
88721a61829SFUJITA Tomonori 
8881da177e4SLinus Torvalds 	return 0;
8891da177e4SLinus Torvalds }
8901da177e4SLinus Torvalds 
8911da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */
8921da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
89321a61829SFUJITA Tomonori 			       int arr_len)
8941da177e4SLinus Torvalds {
89521a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
8961da177e4SLinus Torvalds 		return 0;
897072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
8981da177e4SLinus Torvalds 		return -1;
89921a61829SFUJITA Tomonori 
90021a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
9011da177e4SLinus Torvalds }
9021da177e4SLinus Torvalds 
9031da177e4SLinus Torvalds 
9041da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux   ";
9051da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug      ";
906773642d9SDouglas Gilbert static const char *inq_product_rev = "0186";	/* version less '.' */
907773642d9SDouglas Gilbert static const u64 naa5_comp_a = 0x5222222000000000ULL;
908773642d9SDouglas Gilbert static const u64 naa5_comp_b = 0x5333333000000000ULL;
909773642d9SDouglas Gilbert static const u64 naa5_comp_c = 0x5111111000000000ULL;
9101da177e4SLinus Torvalds 
911cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
9125a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
9135a09e398SHannes Reinecke 			   int target_dev_id, int dev_id_num,
9145a09e398SHannes Reinecke 			   const char * dev_id_str,
915c65b1445SDouglas Gilbert 			   int dev_id_str_len)
9161da177e4SLinus Torvalds {
917c65b1445SDouglas Gilbert 	int num, port_a;
918c65b1445SDouglas Gilbert 	char b[32];
9191da177e4SLinus Torvalds 
920c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
9211da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
9221da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
9231da177e4SLinus Torvalds 	arr[1] = 0x1;
9241da177e4SLinus Torvalds 	arr[2] = 0x0;
9251da177e4SLinus Torvalds 	memcpy(&arr[4], inq_vendor_id, 8);
9261da177e4SLinus Torvalds 	memcpy(&arr[12], inq_product_id, 16);
9271da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
9281da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
9291da177e4SLinus Torvalds 	arr[3] = num;
9301da177e4SLinus Torvalds 	num += 4;
931c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
932c65b1445SDouglas Gilbert 		/* NAA-5, Logical unit identifier (binary) */
933c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* binary (not necessarily sas) */
934c65b1445SDouglas Gilbert 		arr[num++] = 0x3;	/* PIV=0, lu, naa */
935c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
936c65b1445SDouglas Gilbert 		arr[num++] = 0x8;
937773642d9SDouglas Gilbert 		put_unaligned_be64(naa5_comp_b + dev_id_num, arr + num);
938773642d9SDouglas Gilbert 		num += 8;
939c65b1445SDouglas Gilbert 		/* Target relative port number */
940c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
941c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
942c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
943c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
944c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
945c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
946c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
947c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
948c65b1445SDouglas Gilbert 	}
949c65b1445SDouglas Gilbert 	/* NAA-5, Target port identifier */
950c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
951c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
952c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
953c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
954773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_a + port_a, arr + num);
955773642d9SDouglas Gilbert 	num += 8;
9565a09e398SHannes Reinecke 	/* NAA-5, Target port group identifier */
9575a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
9585a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
9595a09e398SHannes Reinecke 	arr[num++] = 0x0;
9605a09e398SHannes Reinecke 	arr[num++] = 0x4;
9615a09e398SHannes Reinecke 	arr[num++] = 0;
9625a09e398SHannes Reinecke 	arr[num++] = 0;
963773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
964773642d9SDouglas Gilbert 	num += 2;
965c65b1445SDouglas Gilbert 	/* NAA-5, Target device identifier */
966c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
967c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
968c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
969c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
970773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_a + target_dev_id, arr + num);
971773642d9SDouglas Gilbert 	num += 8;
972c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
973c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
974c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
975c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
976c65b1445SDouglas Gilbert 	arr[num++] = 24;
977c65b1445SDouglas Gilbert 	memcpy(arr + num, "naa.52222220", 12);
978c65b1445SDouglas Gilbert 	num += 12;
979c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
980c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
981c65b1445SDouglas Gilbert 	num += 8;
982c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
983c65b1445SDouglas Gilbert 	num += 4;
984c65b1445SDouglas Gilbert 	return num;
985c65b1445SDouglas Gilbert }
986c65b1445SDouglas Gilbert 
987c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
988c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
989c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
990c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
991c65b1445SDouglas Gilbert };
992c65b1445SDouglas Gilbert 
993cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
994c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr)
995c65b1445SDouglas Gilbert {
996c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
997c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
998c65b1445SDouglas Gilbert }
999c65b1445SDouglas Gilbert 
1000cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1001c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr)
1002c65b1445SDouglas Gilbert {
1003c65b1445SDouglas Gilbert 	int num = 0;
1004c65b1445SDouglas Gilbert 	const char * na1 = "https://www.kernel.org/config";
1005c65b1445SDouglas Gilbert 	const char * na2 = "http://www.kernel.org/log";
1006c65b1445SDouglas Gilbert 	int plen, olen;
1007c65b1445SDouglas Gilbert 
1008c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1009c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1010c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1011c65b1445SDouglas Gilbert 	olen = strlen(na1);
1012c65b1445SDouglas Gilbert 	plen = olen + 1;
1013c65b1445SDouglas Gilbert 	if (plen % 4)
1014c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1015c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1016c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1017c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1018c65b1445SDouglas Gilbert 	num += plen;
1019c65b1445SDouglas Gilbert 
1020c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1021c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1022c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1023c65b1445SDouglas Gilbert 	olen = strlen(na2);
1024c65b1445SDouglas Gilbert 	plen = olen + 1;
1025c65b1445SDouglas Gilbert 	if (plen % 4)
1026c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1027c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1028c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1029c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1030c65b1445SDouglas Gilbert 	num += plen;
1031c65b1445SDouglas Gilbert 
1032c65b1445SDouglas Gilbert 	return num;
1033c65b1445SDouglas Gilbert }
1034c65b1445SDouglas Gilbert 
1035c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1036c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
1037c65b1445SDouglas Gilbert {
1038c65b1445SDouglas Gilbert 	int num = 0;
1039c65b1445SDouglas Gilbert 	int port_a, port_b;
1040c65b1445SDouglas Gilbert 
1041c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1042c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1043c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1044c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1045c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1046c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1047c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1048c65b1445SDouglas Gilbert 	num += 6;
1049c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1050c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1051c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1052c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1053c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1054c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1055c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
1056773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_a + port_a, arr + num);
1057773642d9SDouglas Gilbert 	num += 8;
1058c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1059c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1060c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1061c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1062c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1063c65b1445SDouglas Gilbert 	num += 6;
1064c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1065c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1066c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1067c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1068c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1069c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1070c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
1071773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_a + port_b, arr + num);
1072773642d9SDouglas Gilbert 	num += 8;
1073c65b1445SDouglas Gilbert 
1074c65b1445SDouglas Gilbert 	return num;
1075c65b1445SDouglas Gilbert }
1076c65b1445SDouglas Gilbert 
1077c65b1445SDouglas Gilbert 
1078c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1079c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1080c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1081c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1082c65b1445SDouglas Gilbert '1','2','3','4',
1083c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1084c65b1445SDouglas Gilbert 0xec,0,0,0,
1085c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1086c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1087c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1088c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1089c65b1445SDouglas Gilbert 0x53,0x41,
1090c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1091c65b1445SDouglas Gilbert 0x20,0x20,
1092c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1093c65b1445SDouglas Gilbert 0x10,0x80,
1094c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1095c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1096c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1097c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1098c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1099c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1100c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1101c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1102c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1103c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1104c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1105c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1106c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1107c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1108c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1109c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1110c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1111c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1112c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1113c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1114c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1115c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1116c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1117c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1118c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1119c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1120c65b1445SDouglas Gilbert };
1121c65b1445SDouglas Gilbert 
1122cbf67842SDouglas Gilbert /* ATA Information VPD page */
1123c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr)
1124c65b1445SDouglas Gilbert {
1125c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1126c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1127c65b1445SDouglas Gilbert }
1128c65b1445SDouglas Gilbert 
1129c65b1445SDouglas Gilbert 
1130c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
11311e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
11321e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11331e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11341e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1135c65b1445SDouglas Gilbert };
1136c65b1445SDouglas Gilbert 
1137cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1138c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr)
1139c65b1445SDouglas Gilbert {
1140ea61fca5SMartin K. Petersen 	unsigned int gran;
1141ea61fca5SMartin K. Petersen 
1142c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1143e308b3d1SMartin K. Petersen 
1144e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
1145773642d9SDouglas Gilbert 	gran = 1 << sdebug_physblk_exp;
1146773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1147e308b3d1SMartin K. Petersen 
1148e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1149773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1150773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
115144d92694SMartin K. Petersen 
1152e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1153773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1154e308b3d1SMartin K. Petersen 
1155773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1156e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1157773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1158e308b3d1SMartin K. Petersen 
1159e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1160773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
116144d92694SMartin K. Petersen 	}
116244d92694SMartin K. Petersen 
1163e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1164773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1165773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
116644d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
116744d92694SMartin K. Petersen 	}
116844d92694SMartin K. Petersen 
1169e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1170773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
11716014759cSMartin K. Petersen 
11725b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1173773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
11745b94e232SMartin K. Petersen 
11755b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
117644d92694SMartin K. Petersen 
1177c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
11781da177e4SLinus Torvalds }
11791da177e4SLinus Torvalds 
11801e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
1181eac6e8e4SMatthew Wilcox static int inquiry_evpd_b1(unsigned char *arr)
1182eac6e8e4SMatthew Wilcox {
1183eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1184eac6e8e4SMatthew Wilcox 	arr[0] = 0;
11851e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
11861e49f785SDouglas Gilbert 	arr[2] = 0;
11871e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
1188eac6e8e4SMatthew Wilcox 
1189eac6e8e4SMatthew Wilcox 	return 0x3c;
1190eac6e8e4SMatthew Wilcox }
11911da177e4SLinus Torvalds 
1192be1dd78dSEric Sandeen /* Logical block provisioning VPD page (SBC-3) */
11936014759cSMartin K. Petersen static int inquiry_evpd_b2(unsigned char *arr)
11946014759cSMartin K. Petersen {
11953f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
11966014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
11976014759cSMartin K. Petersen 
1198773642d9SDouglas Gilbert 	if (sdebug_lbpu)
11996014759cSMartin K. Petersen 		arr[1] = 1 << 7;
12006014759cSMartin K. Petersen 
1201773642d9SDouglas Gilbert 	if (sdebug_lbpws)
12026014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
12036014759cSMartin K. Petersen 
1204773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
12055b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
12065b94e232SMartin K. Petersen 
1207773642d9SDouglas Gilbert 	if (sdebug_lbprz)
1208be1dd78dSEric Sandeen 		arr[1] |= 1 << 2;
1209be1dd78dSEric Sandeen 
12103f0bc3b3SMartin K. Petersen 	return 0x4;
12116014759cSMartin K. Petersen }
12126014759cSMartin K. Petersen 
12131da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1214c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
12151da177e4SLinus Torvalds 
1216c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
12171da177e4SLinus Torvalds {
12181da177e4SLinus Torvalds 	unsigned char pq_pdt;
12195a09e398SHannes Reinecke 	unsigned char * arr;
122001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
12215a09e398SHannes Reinecke 	int alloc_len, n, ret;
1222c2248fc9SDouglas Gilbert 	bool have_wlun;
12231da177e4SLinus Torvalds 
1224773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
12256f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
12266f3cbf55SDouglas Gilbert 	if (! arr)
12276f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
122834d55434STomas Winkler 	have_wlun = (scp->device->lun == SCSI_W_LUN_REPORT_LUNS);
1229c2248fc9SDouglas Gilbert 	if (have_wlun)
1230c65b1445SDouglas Gilbert 		pq_pdt = 0x1e;	/* present, wlun */
1231773642d9SDouglas Gilbert 	else if (sdebug_no_lun_0 && (0 == devip->lun))
1232c65b1445SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, no device type */
1233c65b1445SDouglas Gilbert 	else
1234773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
12351da177e4SLinus Torvalds 	arr[0] = pq_pdt;
12361da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
123722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
12385a09e398SHannes Reinecke 		kfree(arr);
12391da177e4SLinus Torvalds 		return check_condition_result;
12401da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
12415a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1242c65b1445SDouglas Gilbert 		char lu_id_str[6];
1243c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
12441da177e4SLinus Torvalds 
12455a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
12465a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1247773642d9SDouglas Gilbert 		if (0 == sdebug_vpd_use_hostno)
124823183910SDouglas Gilbert 			host_no = 0;
1249c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1250c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1251c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1252c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1253c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
12541da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1255c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1256c65b1445SDouglas Gilbert 			n = 4;
1257c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1258c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1259c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1260c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1261c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1262c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1263c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1264c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1265c65b1445SDouglas Gilbert 			arr[n++] = 0x89;  /* ATA information */
1266c65b1445SDouglas Gilbert 			arr[n++] = 0xb0;  /* Block limits (SBC) */
1267eac6e8e4SMatthew Wilcox 			arr[n++] = 0xb1;  /* Block characteristics (SBC) */
12685b94e232SMartin K. Petersen 			if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
12695b94e232SMartin K. Petersen 				arr[n++] = 0xb2;
1270c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
12711da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1272c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
12731da177e4SLinus Torvalds 			arr[3] = len;
1274c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
12751da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1276c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
12775a09e398SHannes Reinecke 			arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
12785a09e398SHannes Reinecke 						 target_dev_id, lu_id_num,
12795a09e398SHannes Reinecke 						 lu_id_str, len);
1280c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1281c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1282c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_84(&arr[4]);
1283c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1284c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1285c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_85(&arr[4]);
1286c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1287c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1288c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
1289773642d9SDouglas Gilbert 			if (sdebug_dif == SD_DIF_TYPE3_PROTECTION)
1290c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1291773642d9SDouglas Gilbert 			else if (sdebug_dif)
1292c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1293c6a44287SMartin K. Petersen 			else
1294c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1295c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1296c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1297c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1298c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1299c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1300c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1301c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1302c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1303c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1304c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1305c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1306c65b1445SDouglas Gilbert 		} else if (0x89 == cmd[2]) { /* ATA information */
1307c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1308c65b1445SDouglas Gilbert 			n = inquiry_evpd_89(&arr[4]);
1309773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1310c65b1445SDouglas Gilbert 		} else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1311c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1312c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_b0(&arr[4]);
1313eac6e8e4SMatthew Wilcox 		} else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
1314eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
1315eac6e8e4SMatthew Wilcox 			arr[3] = inquiry_evpd_b1(&arr[4]);
13165b94e232SMartin K. Petersen 		} else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
13176014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
13186014759cSMartin K. Petersen 			arr[3] = inquiry_evpd_b2(&arr[4]);
13191da177e4SLinus Torvalds 		} else {
132022017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
13215a09e398SHannes Reinecke 			kfree(arr);
13221da177e4SLinus Torvalds 			return check_condition_result;
13231da177e4SLinus Torvalds 		}
1324773642d9SDouglas Gilbert 		len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
13255a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1326c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
13275a09e398SHannes Reinecke 		kfree(arr);
13285a09e398SHannes Reinecke 		return ret;
13291da177e4SLinus Torvalds 	}
13301da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1331773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1332773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
13331da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
13341da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1335f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1336773642d9SDouglas Gilbert 	if (0 == sdebug_vpd_use_hostno)
13375a09e398SHannes Reinecke 		arr[5] = 0x10; /* claim: implicit TGPS */
1338c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
13391da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1340c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
13411da177e4SLinus Torvalds 	memcpy(&arr[8], inq_vendor_id, 8);
13421da177e4SLinus Torvalds 	memcpy(&arr[16], inq_product_id, 16);
13431da177e4SLinus Torvalds 	memcpy(&arr[32], inq_product_rev, 4);
13441da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1345e46b0344SDouglas Gilbert 	arr[58] = 0x0; arr[59] = 0xa2;  /* SAM-5 rev 4 */
1346e46b0344SDouglas Gilbert 	arr[60] = 0x4; arr[61] = 0x68;  /* SPC-4 rev 37 */
1347c65b1445SDouglas Gilbert 	n = 62;
1348773642d9SDouglas Gilbert 	if (sdebug_ptype == 0) {
1349e46b0344SDouglas Gilbert 		arr[n++] = 0x4; arr[n++] = 0xc5; /* SBC-4 rev 36 */
1350773642d9SDouglas Gilbert 	} else if (sdebug_ptype == 1) {
1351e46b0344SDouglas Gilbert 		arr[n++] = 0x5; arr[n++] = 0x25; /* SSC-4 rev 3 */
13521da177e4SLinus Torvalds 	}
1353e46b0344SDouglas Gilbert 	arr[n++] = 0x20; arr[n++] = 0xe6;  /* SPL-3 rev 7 */
13545a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
13551da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
13565a09e398SHannes Reinecke 	kfree(arr);
13575a09e398SHannes Reinecke 	return ret;
13581da177e4SLinus Torvalds }
13591da177e4SLinus Torvalds 
1360fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1361fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1362fd32119bSDouglas Gilbert 
13631da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp,
13641da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip)
13651da177e4SLinus Torvalds {
13661da177e4SLinus Torvalds 	unsigned char * sbuff;
136701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1368cbf67842SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
13692492fc09STomas Winkler 	bool dsense;
13701da177e4SLinus Torvalds 	int len = 18;
13711da177e4SLinus Torvalds 
1372c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1373c2248fc9SDouglas Gilbert 	dsense = !!(cmd[1] & 1);
1374cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
1375c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1376c2248fc9SDouglas Gilbert 		if (dsense) {
1377c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1378c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1379c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
1380c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
1381c2248fc9SDouglas Gilbert 			len = 8;
1382c65b1445SDouglas Gilbert 		} else {
1383c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1384c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1385c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1386c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
1387c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
1388c65b1445SDouglas Gilbert 		}
1389c65b1445SDouglas Gilbert 	} else {
1390cbf67842SDouglas Gilbert 		memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
1391773642d9SDouglas Gilbert 		if (arr[0] >= 0x70 && dsense == sdebug_dsense)
1392c2248fc9SDouglas Gilbert 			;	/* have sense and formats match */
1393c2248fc9SDouglas Gilbert 		else if (arr[0] <= 0x70) {
1394c2248fc9SDouglas Gilbert 			if (dsense) {
1395c2248fc9SDouglas Gilbert 				memset(arr, 0, 8);
1396c2248fc9SDouglas Gilbert 				arr[0] = 0x72;
1397c2248fc9SDouglas Gilbert 				len = 8;
1398c2248fc9SDouglas Gilbert 			} else {
1399c2248fc9SDouglas Gilbert 				memset(arr, 0, 18);
1400c2248fc9SDouglas Gilbert 				arr[0] = 0x70;
1401c2248fc9SDouglas Gilbert 				arr[7] = 0xa;
1402c2248fc9SDouglas Gilbert 			}
1403c2248fc9SDouglas Gilbert 		} else if (dsense) {
1404c2248fc9SDouglas Gilbert 			memset(arr, 0, 8);
14051da177e4SLinus Torvalds 			arr[0] = 0x72;
14061da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
14071da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
14081da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
14091da177e4SLinus Torvalds 			len = 8;
1410c2248fc9SDouglas Gilbert 		} else {
1411c2248fc9SDouglas Gilbert 			memset(arr, 0, 18);
1412c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1413c2248fc9SDouglas Gilbert 			arr[2] = sbuff[1];
1414c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1415c2248fc9SDouglas Gilbert 			arr[12] = sbuff[1];
1416c2248fc9SDouglas Gilbert 			arr[13] = sbuff[3];
1417c65b1445SDouglas Gilbert 		}
1418c2248fc9SDouglas Gilbert 
1419c65b1445SDouglas Gilbert 	}
1420cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
14211da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
14221da177e4SLinus Torvalds }
14231da177e4SLinus Torvalds 
1424c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp,
1425c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
1426c65b1445SDouglas Gilbert {
142701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1428c2248fc9SDouglas Gilbert 	int power_cond, start;
1429c65b1445SDouglas Gilbert 
1430c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1431c65b1445SDouglas Gilbert 	if (power_cond) {
143222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1433c65b1445SDouglas Gilbert 		return check_condition_result;
1434c65b1445SDouglas Gilbert 	}
1435c65b1445SDouglas Gilbert 	start = cmd[4] & 1;
1436c65b1445SDouglas Gilbert 	if (start == devip->stopped)
1437c65b1445SDouglas Gilbert 		devip->stopped = !start;
1438c65b1445SDouglas Gilbert 	return 0;
1439c65b1445SDouglas Gilbert }
1440c65b1445SDouglas Gilbert 
144128898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
144228898873SFUJITA Tomonori {
1443773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1444773642d9SDouglas Gilbert 
1445773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1446773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1447773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
144828898873SFUJITA Tomonori 	else
144928898873SFUJITA Tomonori 		return sdebug_store_sectors;
145028898873SFUJITA Tomonori }
145128898873SFUJITA Tomonori 
14521da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
14531da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp,
14541da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
14551da177e4SLinus Torvalds {
14561da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1457c65b1445SDouglas Gilbert 	unsigned int capac;
14581da177e4SLinus Torvalds 
1459c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
146028898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
14611da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1462c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1463c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1464773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1465773642d9SDouglas Gilbert 	} else
1466773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1467773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
14681da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
14691da177e4SLinus Torvalds }
14701da177e4SLinus Torvalds 
1471c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1472c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp,
1473c65b1445SDouglas Gilbert 			  struct sdebug_dev_info * devip)
1474c65b1445SDouglas Gilbert {
147501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1476c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1477773642d9SDouglas Gilbert 	int alloc_len;
1478c65b1445SDouglas Gilbert 
1479773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1480c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
148128898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1482c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1483773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1484773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1485773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1486773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
148744d92694SMartin K. Petersen 
1488be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
14895b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1490773642d9SDouglas Gilbert 		if (sdebug_lbprz)
1491be1dd78dSEric Sandeen 			arr[14] |= 0x40; /* LBPRZ */
1492be1dd78dSEric Sandeen 	}
149344d92694SMartin K. Petersen 
1494773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1495c6a44287SMartin K. Petersen 
1496773642d9SDouglas Gilbert 	if (sdebug_dif) {
1497773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1498c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1499c6a44287SMartin K. Petersen 	}
1500c6a44287SMartin K. Petersen 
1501c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1502c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1503c65b1445SDouglas Gilbert }
1504c65b1445SDouglas Gilbert 
15055a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
15065a09e398SHannes Reinecke 
15075a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp,
15085a09e398SHannes Reinecke 			      struct sdebug_dev_info * devip)
15095a09e398SHannes Reinecke {
151001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
15115a09e398SHannes Reinecke 	unsigned char * arr;
15125a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
15135a09e398SHannes Reinecke 	int n, ret, alen, rlen;
15145a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
15155a09e398SHannes Reinecke 
1516773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
15176f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
15186f3cbf55SDouglas Gilbert 	if (! arr)
15196f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
15205a09e398SHannes Reinecke 	/*
15215a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
15225a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
15235a09e398SHannes Reinecke 	 * So we create two port groups with one port each
15245a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
15255a09e398SHannes Reinecke 	 */
15265a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
15275a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
15285a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
15295a09e398SHannes Reinecke 			(devip->channel & 0x7f);
15305a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
15315a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
15325a09e398SHannes Reinecke 
15335a09e398SHannes Reinecke 	/*
15345a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
15355a09e398SHannes Reinecke 	 */
15365a09e398SHannes Reinecke 	n = 4;
1537773642d9SDouglas Gilbert 	if (0 == sdebug_vpd_use_hostno) {
15385a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
15395a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
15405a09e398SHannes Reinecke 	} else {
15415a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1542773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
15435a09e398SHannes Reinecke 	}
1544773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1545773642d9SDouglas Gilbert 	n += 2;
15465a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
15475a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
15485a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
15495a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
15505a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
15515a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1552773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1553773642d9SDouglas Gilbert 	n += 2;
15545a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
15555a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1556773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1557773642d9SDouglas Gilbert 	n += 2;
15585a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
15595a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
15605a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
15615a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
15625a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
15635a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1564773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1565773642d9SDouglas Gilbert 	n += 2;
15665a09e398SHannes Reinecke 
15675a09e398SHannes Reinecke 	rlen = n - 4;
1568773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
15695a09e398SHannes Reinecke 
15705a09e398SHannes Reinecke 	/*
15715a09e398SHannes Reinecke 	 * Return the smallest value of either
15725a09e398SHannes Reinecke 	 * - The allocated length
15735a09e398SHannes Reinecke 	 * - The constructed command length
15745a09e398SHannes Reinecke 	 * - The maximum array size
15755a09e398SHannes Reinecke 	 */
15765a09e398SHannes Reinecke 	rlen = min(alen,n);
15775a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
15785a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
15795a09e398SHannes Reinecke 	kfree(arr);
15805a09e398SHannes Reinecke 	return ret;
15815a09e398SHannes Reinecke }
15825a09e398SHannes Reinecke 
1583fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1584fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
158538d5c833SDouglas Gilbert {
158638d5c833SDouglas Gilbert 	bool rctd;
158738d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
158838d5c833SDouglas Gilbert 	u16 req_sa, u;
158938d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
159038d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
159138d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
159238d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
159338d5c833SDouglas Gilbert 	u8 *arr;
159438d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
159538d5c833SDouglas Gilbert 
159638d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
159738d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
159838d5c833SDouglas Gilbert 	req_opcode = cmd[3];
159938d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
160038d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
16016d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
160238d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
160338d5c833SDouglas Gilbert 		return check_condition_result;
160438d5c833SDouglas Gilbert 	}
160538d5c833SDouglas Gilbert 	if (alloc_len > 8192)
160638d5c833SDouglas Gilbert 		a_len = 8192;
160738d5c833SDouglas Gilbert 	else
160838d5c833SDouglas Gilbert 		a_len = alloc_len;
160999531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
161038d5c833SDouglas Gilbert 	if (NULL == arr) {
161138d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
161238d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
161338d5c833SDouglas Gilbert 		return check_condition_result;
161438d5c833SDouglas Gilbert 	}
161538d5c833SDouglas Gilbert 	switch (reporting_opts) {
161638d5c833SDouglas Gilbert 	case 0:	/* all commands */
161738d5c833SDouglas Gilbert 		/* count number of commands */
161838d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
161938d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
162038d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
162138d5c833SDouglas Gilbert 				continue;
162238d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
162338d5c833SDouglas Gilbert 		}
162438d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
162538d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
162638d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
162738d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
162838d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
162938d5c833SDouglas Gilbert 				continue;
163038d5c833SDouglas Gilbert 			na = oip->num_attached;
163138d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
163238d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
163338d5c833SDouglas Gilbert 			if (rctd)
163438d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
163538d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
163638d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
163738d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
163838d5c833SDouglas Gilbert 			if (rctd)
163938d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
164038d5c833SDouglas Gilbert 			r_oip = oip;
164138d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
164238d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
164338d5c833SDouglas Gilbert 					continue;
164438d5c833SDouglas Gilbert 				offset += bump;
164538d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
164638d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
164738d5c833SDouglas Gilbert 				if (rctd)
164838d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
164938d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
165038d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
165138d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
165238d5c833SDouglas Gilbert 						   arr + offset + 6);
165338d5c833SDouglas Gilbert 				if (rctd)
165438d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
165538d5c833SDouglas Gilbert 							   arr + offset + 8);
165638d5c833SDouglas Gilbert 			}
165738d5c833SDouglas Gilbert 			oip = r_oip;
165838d5c833SDouglas Gilbert 			offset += bump;
165938d5c833SDouglas Gilbert 		}
166038d5c833SDouglas Gilbert 		break;
166138d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
166238d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
166338d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
166438d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
166538d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
166638d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
166738d5c833SDouglas Gilbert 			supp = 1;
166838d5c833SDouglas Gilbert 			offset = 4;
166938d5c833SDouglas Gilbert 		} else {
167038d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
167138d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
167238d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
167338d5c833SDouglas Gilbert 							     2, 2);
167438d5c833SDouglas Gilbert 					kfree(arr);
167538d5c833SDouglas Gilbert 					return check_condition_result;
167638d5c833SDouglas Gilbert 				}
167738d5c833SDouglas Gilbert 				req_sa = 0;
167838d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
167938d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
168038d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
168138d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
168238d5c833SDouglas Gilbert 				return check_condition_result;
168338d5c833SDouglas Gilbert 			}
168438d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
168538d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
168638d5c833SDouglas Gilbert 				supp = 3;
168738d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
168838d5c833SDouglas Gilbert 				na = oip->num_attached;
168938d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
169038d5c833SDouglas Gilbert 				     ++k, ++oip) {
169138d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
169238d5c833SDouglas Gilbert 						break;
169338d5c833SDouglas Gilbert 				}
169438d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
169538d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
169638d5c833SDouglas Gilbert 				na = oip->num_attached;
169738d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
169838d5c833SDouglas Gilbert 				     ++k, ++oip) {
169938d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
170038d5c833SDouglas Gilbert 						break;
170138d5c833SDouglas Gilbert 				}
170238d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
170338d5c833SDouglas Gilbert 			} else
170438d5c833SDouglas Gilbert 				supp = 3;
170538d5c833SDouglas Gilbert 			if (3 == supp) {
170638d5c833SDouglas Gilbert 				u = oip->len_mask[0];
170738d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
170838d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
170938d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
171038d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
171138d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
171238d5c833SDouglas Gilbert 				offset = 4 + u;
171338d5c833SDouglas Gilbert 			} else
171438d5c833SDouglas Gilbert 				offset = 4;
171538d5c833SDouglas Gilbert 		}
171638d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
171738d5c833SDouglas Gilbert 		if (rctd) {
171838d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
171938d5c833SDouglas Gilbert 			offset += 12;
172038d5c833SDouglas Gilbert 		}
172138d5c833SDouglas Gilbert 		break;
172238d5c833SDouglas Gilbert 	default:
172338d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
172438d5c833SDouglas Gilbert 		kfree(arr);
172538d5c833SDouglas Gilbert 		return check_condition_result;
172638d5c833SDouglas Gilbert 	}
172738d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
172838d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
172938d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
173038d5c833SDouglas Gilbert 	kfree(arr);
173138d5c833SDouglas Gilbert 	return errsts;
173238d5c833SDouglas Gilbert }
173338d5c833SDouglas Gilbert 
1734fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1735fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
173638d5c833SDouglas Gilbert {
173738d5c833SDouglas Gilbert 	bool repd;
173838d5c833SDouglas Gilbert 	u32 alloc_len, len;
173938d5c833SDouglas Gilbert 	u8 arr[16];
174038d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
174138d5c833SDouglas Gilbert 
174238d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
174338d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
174438d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
174538d5c833SDouglas Gilbert 	if (alloc_len < 4) {
174638d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
174738d5c833SDouglas Gilbert 		return check_condition_result;
174838d5c833SDouglas Gilbert 	}
174938d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
175038d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
175138d5c833SDouglas Gilbert 	if (repd) {
175238d5c833SDouglas Gilbert 		arr[3] = 0xc;
175338d5c833SDouglas Gilbert 		len = 16;
175438d5c833SDouglas Gilbert 	} else
175538d5c833SDouglas Gilbert 		len = 4;
175638d5c833SDouglas Gilbert 
175738d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
175838d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
175938d5c833SDouglas Gilbert }
176038d5c833SDouglas Gilbert 
17611da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
17621da177e4SLinus Torvalds 
17631da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
17641da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
17651da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
17661da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
17671da177e4SLinus Torvalds 
17681da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
17691da177e4SLinus Torvalds 	if (1 == pcontrol)
17701da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
17711da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
17721da177e4SLinus Torvalds }
17731da177e4SLinus Torvalds 
17741da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
17751da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
17761da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
17771da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
17781da177e4SLinus Torvalds 
17791da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
17801da177e4SLinus Torvalds 	if (1 == pcontrol)
17811da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
17821da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
17831da177e4SLinus Torvalds }
17841da177e4SLinus Torvalds 
17851da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target)
17861da177e4SLinus Torvalds {       /* Format device page for mode_sense */
17871da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
17881da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
17891da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
17901da177e4SLinus Torvalds 
17911da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
1792773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
1793773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
1794773642d9SDouglas Gilbert 	if (sdebug_removable)
17951da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
17961da177e4SLinus Torvalds 	if (1 == pcontrol)
17971da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
17981da177e4SLinus Torvalds 	return sizeof(format_pg);
17991da177e4SLinus Torvalds }
18001da177e4SLinus Torvalds 
1801fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1802fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1803fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
1804fd32119bSDouglas Gilbert 
18051da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
18061da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
1807cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1808cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1809cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
18101da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
18111da177e4SLinus Torvalds 
1812773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
1813cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
18141da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
18151da177e4SLinus Torvalds 	if (1 == pcontrol)
1816cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1817cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
1818cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
18191da177e4SLinus Torvalds 	return sizeof(caching_pg);
18201da177e4SLinus Torvalds }
18211da177e4SLinus Torvalds 
1822fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
1823fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
1824fd32119bSDouglas Gilbert 
18251da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
18261da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
1827c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1828c65b1445SDouglas Gilbert 				        0, 0, 0, 0};
1829c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
18301da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
18311da177e4SLinus Torvalds 
1832773642d9SDouglas Gilbert 	if (sdebug_dsense)
18331da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
1834c65b1445SDouglas Gilbert 	else
1835c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
1836c6a44287SMartin K. Petersen 
1837773642d9SDouglas Gilbert 	if (sdebug_ato)
1838c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1839c6a44287SMartin K. Petersen 
18401da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
18411da177e4SLinus Torvalds 	if (1 == pcontrol)
1842c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1843c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1844c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
18451da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
18461da177e4SLinus Torvalds }
18471da177e4SLinus Torvalds 
1848c65b1445SDouglas Gilbert 
18491da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
18501da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
1851c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
18521da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
1853c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1854c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
1855c65b1445SDouglas Gilbert 
18561da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
18571da177e4SLinus Torvalds 	if (1 == pcontrol)
1858c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1859c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1860c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
18611da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
18621da177e4SLinus Torvalds }
18631da177e4SLinus Torvalds 
1864c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1865c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
1866c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1867c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1868c65b1445SDouglas Gilbert 
1869c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1870c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1871c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1872c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
1873c65b1445SDouglas Gilbert }
1874c65b1445SDouglas Gilbert 
1875c65b1445SDouglas Gilbert 
1876c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1877c65b1445SDouglas Gilbert 			      int target_dev_id)
1878c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
1879c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1880c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1881773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1882773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1883c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
1884c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1885c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1886c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1887773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1888773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1889c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
1890c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1891c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1892c65b1445SDouglas Gilbert 		};
1893c65b1445SDouglas Gilbert 	int port_a, port_b;
1894c65b1445SDouglas Gilbert 
1895773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 16);
1896773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 24);
1897773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 64);
1898773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 72);
1899c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1900c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1901c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1902773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
1903773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
1904c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1905c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1906c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
1907c65b1445SDouglas Gilbert }
1908c65b1445SDouglas Gilbert 
1909c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1910c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
1911c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1912c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1913c65b1445SDouglas Gilbert 		};
1914c65b1445SDouglas Gilbert 
1915c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1916c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1917c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1918c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
1919c65b1445SDouglas Gilbert }
1920c65b1445SDouglas Gilbert 
19211da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
19221da177e4SLinus Torvalds 
1923fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
1924fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
19251da177e4SLinus Torvalds {
192623183910SDouglas Gilbert 	unsigned char dbd, llbaa;
192723183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
19281da177e4SLinus Torvalds 	unsigned char dev_spec;
1929773642d9SDouglas Gilbert 	int alloc_len, msense_6, offset, len, target_dev_id;
1930c2248fc9SDouglas Gilbert 	int target = scp->device->id;
19311da177e4SLinus Torvalds 	unsigned char * ap;
19321da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
193301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
19341da177e4SLinus Torvalds 
193523183910SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);
19361da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
19371da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
19381da177e4SLinus Torvalds 	subpcode = cmd[3];
19391da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
194023183910SDouglas Gilbert 	llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1941773642d9SDouglas Gilbert 	if ((0 == sdebug_ptype) && (0 == dbd))
194223183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
194323183910SDouglas Gilbert 	else
194423183910SDouglas Gilbert 		bd_len = 0;
1945773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
19461da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
19471da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
1948cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
19491da177e4SLinus Torvalds 		return check_condition_result;
19501da177e4SLinus Torvalds 	}
1951c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1952c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
195323183910SDouglas Gilbert 	/* set DPOFUA bit for disks */
1954773642d9SDouglas Gilbert 	if (0 == sdebug_ptype)
1955fd32119bSDouglas Gilbert 		dev_spec = 0x10;	/* would be 0x90 if read-only */
195623183910SDouglas Gilbert 	else
195723183910SDouglas Gilbert 		dev_spec = 0x0;
19581da177e4SLinus Torvalds 	if (msense_6) {
19591da177e4SLinus Torvalds 		arr[2] = dev_spec;
196023183910SDouglas Gilbert 		arr[3] = bd_len;
19611da177e4SLinus Torvalds 		offset = 4;
19621da177e4SLinus Torvalds 	} else {
19631da177e4SLinus Torvalds 		arr[3] = dev_spec;
196423183910SDouglas Gilbert 		if (16 == bd_len)
196523183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
196623183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
19671da177e4SLinus Torvalds 		offset = 8;
19681da177e4SLinus Torvalds 	}
19691da177e4SLinus Torvalds 	ap = arr + offset;
197028898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
197128898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
197228898873SFUJITA Tomonori 
197323183910SDouglas Gilbert 	if (8 == bd_len) {
1974773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
1975773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
1976773642d9SDouglas Gilbert 		else
1977773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
1978773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
197923183910SDouglas Gilbert 		offset += bd_len;
198023183910SDouglas Gilbert 		ap = arr + offset;
198123183910SDouglas Gilbert 	} else if (16 == bd_len) {
1982773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
1983773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
198423183910SDouglas Gilbert 		offset += bd_len;
198523183910SDouglas Gilbert 		ap = arr + offset;
198623183910SDouglas Gilbert 	}
19871da177e4SLinus Torvalds 
1988c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1989c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
199022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
19911da177e4SLinus Torvalds 		return check_condition_result;
19921da177e4SLinus Torvalds 	}
19931da177e4SLinus Torvalds 	switch (pcode) {
19941da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
19951da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
19961da177e4SLinus Torvalds 		offset += len;
19971da177e4SLinus Torvalds 		break;
19981da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
19991da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
20001da177e4SLinus Torvalds 		offset += len;
20011da177e4SLinus Torvalds 		break;
20021da177e4SLinus Torvalds         case 0x3:       /* Format device page, direct access */
20031da177e4SLinus Torvalds                 len = resp_format_pg(ap, pcontrol, target);
20041da177e4SLinus Torvalds                 offset += len;
20051da177e4SLinus Torvalds                 break;
20061da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
20071da177e4SLinus Torvalds 		len = resp_caching_pg(ap, pcontrol, target);
20081da177e4SLinus Torvalds 		offset += len;
20091da177e4SLinus Torvalds 		break;
20101da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
20111da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
20121da177e4SLinus Torvalds 		offset += len;
20131da177e4SLinus Torvalds 		break;
2014c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2015c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
201622017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2017c65b1445SDouglas Gilbert 			return check_condition_result;
2018c65b1445SDouglas Gilbert 	        }
2019c65b1445SDouglas Gilbert 		len = 0;
2020c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2021c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2022c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2023c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2024c65b1445SDouglas Gilbert 						  target_dev_id);
2025c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2026c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2027c65b1445SDouglas Gilbert 		offset += len;
2028c65b1445SDouglas Gilbert 		break;
20291da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
20301da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
20311da177e4SLinus Torvalds 		offset += len;
20321da177e4SLinus Torvalds 		break;
20331da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2034c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
20351da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
20361da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
20371da177e4SLinus Torvalds 			len += resp_format_pg(ap + len, pcontrol, target);
20381da177e4SLinus Torvalds 			len += resp_caching_pg(ap + len, pcontrol, target);
20391da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2040c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2041c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2042c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2043c65b1445SDouglas Gilbert 						  target, target_dev_id);
2044c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2045c65b1445SDouglas Gilbert 			}
20461da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2047c65b1445SDouglas Gilbert 		} else {
204822017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2049c65b1445SDouglas Gilbert 			return check_condition_result;
2050c65b1445SDouglas Gilbert                 }
20511da177e4SLinus Torvalds 		offset += len;
20521da177e4SLinus Torvalds 		break;
20531da177e4SLinus Torvalds 	default:
205422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
20551da177e4SLinus Torvalds 		return check_condition_result;
20561da177e4SLinus Torvalds 	}
20571da177e4SLinus Torvalds 	if (msense_6)
20581da177e4SLinus Torvalds 		arr[0] = offset - 1;
2059773642d9SDouglas Gilbert 	else
2060773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
20611da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
20621da177e4SLinus Torvalds }
20631da177e4SLinus Torvalds 
2064c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2065c65b1445SDouglas Gilbert 
2066fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2067fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2068c65b1445SDouglas Gilbert {
2069c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2070c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2071c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
207201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2073c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2074c65b1445SDouglas Gilbert 
2075c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2076c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2077c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2078773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2079c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
208022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2081c65b1445SDouglas Gilbert 		return check_condition_result;
2082c65b1445SDouglas Gilbert 	}
2083c65b1445SDouglas Gilbert         res = fetch_to_dev_buffer(scp, arr, param_len);
2084c65b1445SDouglas Gilbert         if (-1 == res)
2085773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2086773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2087cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2088cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2089cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2090773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2091773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
209223183910SDouglas Gilbert 	if (md_len > 2) {
209322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2094c65b1445SDouglas Gilbert 		return check_condition_result;
2095c65b1445SDouglas Gilbert 	}
2096c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2097c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2098c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2099c65b1445SDouglas Gilbert 	if (ps) {
210022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2101c65b1445SDouglas Gilbert 		return check_condition_result;
2102c65b1445SDouglas Gilbert 	}
2103c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2104773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2105c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2106c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2107cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2108c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2109c65b1445SDouglas Gilbert 		return check_condition_result;
2110c65b1445SDouglas Gilbert 	}
2111c65b1445SDouglas Gilbert 	switch (mpage) {
2112cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2113cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2114cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2115cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2116cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2117cbf67842SDouglas Gilbert 		}
2118cbf67842SDouglas Gilbert 		break;
2119c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2120c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2121c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2122c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
2123773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2124cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2125c65b1445SDouglas Gilbert 		}
2126c65b1445SDouglas Gilbert 		break;
2127c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2128c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2129c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2130c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2131cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2132c65b1445SDouglas Gilbert 		}
2133c65b1445SDouglas Gilbert 		break;
2134c65b1445SDouglas Gilbert 	default:
2135c65b1445SDouglas Gilbert 		break;
2136c65b1445SDouglas Gilbert 	}
213722017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2138c65b1445SDouglas Gilbert 	return check_condition_result;
2139cbf67842SDouglas Gilbert set_mode_changed_ua:
2140cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2141cbf67842SDouglas Gilbert 	return 0;
2142c65b1445SDouglas Gilbert }
2143c65b1445SDouglas Gilbert 
2144c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr)
2145c65b1445SDouglas Gilbert {
2146c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2147c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2148c65b1445SDouglas Gilbert 		};
2149c65b1445SDouglas Gilbert 
2150c65b1445SDouglas Gilbert         memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2151c65b1445SDouglas Gilbert         return sizeof(temp_l_pg);
2152c65b1445SDouglas Gilbert }
2153c65b1445SDouglas Gilbert 
2154c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr)
2155c65b1445SDouglas Gilbert {
2156c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2157c65b1445SDouglas Gilbert 		};
2158c65b1445SDouglas Gilbert 
2159c65b1445SDouglas Gilbert         memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2160c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2161c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2162c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2163c65b1445SDouglas Gilbert 	}
2164c65b1445SDouglas Gilbert         return sizeof(ie_l_pg);
2165c65b1445SDouglas Gilbert }
2166c65b1445SDouglas Gilbert 
2167c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2168c65b1445SDouglas Gilbert 
2169c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp,
2170c65b1445SDouglas Gilbert                           struct sdebug_dev_info * devip)
2171c65b1445SDouglas Gilbert {
2172c2248fc9SDouglas Gilbert 	int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n;
2173c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
217401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2175c65b1445SDouglas Gilbert 
2176c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2177c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2178c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2179c65b1445SDouglas Gilbert 	if (ppc || sp) {
218022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2181c65b1445SDouglas Gilbert 		return check_condition_result;
2182c65b1445SDouglas Gilbert 	}
2183c65b1445SDouglas Gilbert 	pcontrol = (cmd[2] & 0xc0) >> 6;
2184c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
218523183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2186773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2187c65b1445SDouglas Gilbert 	arr[0] = pcode;
218823183910SDouglas Gilbert 	if (0 == subpcode) {
2189c65b1445SDouglas Gilbert 		switch (pcode) {
2190c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2191c65b1445SDouglas Gilbert 			n = 4;
2192c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2193c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2194c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2195c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2196c65b1445SDouglas Gilbert 			break;
2197c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2198c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2199c65b1445SDouglas Gilbert 			break;
2200c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2201c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2202c65b1445SDouglas Gilbert 			break;
2203c65b1445SDouglas Gilbert 		default:
220422017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2205c65b1445SDouglas Gilbert 			return check_condition_result;
2206c65b1445SDouglas Gilbert 		}
220723183910SDouglas Gilbert 	} else if (0xff == subpcode) {
220823183910SDouglas Gilbert 		arr[0] |= 0x40;
220923183910SDouglas Gilbert 		arr[1] = subpcode;
221023183910SDouglas Gilbert 		switch (pcode) {
221123183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
221223183910SDouglas Gilbert 			n = 4;
221323183910SDouglas Gilbert 			arr[n++] = 0x0;
221423183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
221523183910SDouglas Gilbert 			arr[n++] = 0x0;
221623183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
221723183910SDouglas Gilbert 			arr[n++] = 0xd;
221823183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
221923183910SDouglas Gilbert 			arr[n++] = 0x2f;
222023183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
222123183910SDouglas Gilbert 			arr[3] = n - 4;
222223183910SDouglas Gilbert 			break;
222323183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
222423183910SDouglas Gilbert 			n = 4;
222523183910SDouglas Gilbert 			arr[n++] = 0xd;
222623183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
222723183910SDouglas Gilbert 			arr[3] = n - 4;
222823183910SDouglas Gilbert 			break;
222923183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
223023183910SDouglas Gilbert 			n = 4;
223123183910SDouglas Gilbert 			arr[n++] = 0x2f;
223223183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
223323183910SDouglas Gilbert 			arr[3] = n - 4;
223423183910SDouglas Gilbert 			break;
223523183910SDouglas Gilbert 		default:
223622017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
223723183910SDouglas Gilbert 			return check_condition_result;
223823183910SDouglas Gilbert 		}
223923183910SDouglas Gilbert 	} else {
224022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
224123183910SDouglas Gilbert 		return check_condition_result;
224223183910SDouglas Gilbert 	}
2243773642d9SDouglas Gilbert 	len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
2244c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
2245c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
2246c65b1445SDouglas Gilbert }
2247c65b1445SDouglas Gilbert 
2248cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp,
224919789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
22501da177e4SLinus Torvalds {
2251c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
225222017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
22531da177e4SLinus Torvalds 		return check_condition_result;
22541da177e4SLinus Torvalds 	}
2255c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2256c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
225722017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2258cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2259c65b1445SDouglas Gilbert 		return check_condition_result;
2260c65b1445SDouglas Gilbert 	}
226119789100SFUJITA Tomonori 	return 0;
226219789100SFUJITA Tomonori }
226319789100SFUJITA Tomonori 
2264a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
2265fd32119bSDouglas Gilbert static int do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num,
2266fd32119bSDouglas Gilbert 			    bool do_write)
226719789100SFUJITA Tomonori {
226819789100SFUJITA Tomonori 	int ret;
2269c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2270a4517511SAkinobu Mita 	struct scsi_data_buffer *sdb;
2271a4517511SAkinobu Mita 	enum dma_data_direction dir;
227219789100SFUJITA Tomonori 
2273c2248fc9SDouglas Gilbert 	if (do_write) {
2274a4517511SAkinobu Mita 		sdb = scsi_out(scmd);
2275a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
2276a4517511SAkinobu Mita 	} else {
2277a4517511SAkinobu Mita 		sdb = scsi_in(scmd);
2278a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2279a4517511SAkinobu Mita 	}
2280a4517511SAkinobu Mita 
2281a4517511SAkinobu Mita 	if (!sdb->length)
2282a4517511SAkinobu Mita 		return 0;
2283a4517511SAkinobu Mita 	if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2284a4517511SAkinobu Mita 		return -1;
228519789100SFUJITA Tomonori 
228619789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
228719789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
228819789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
228919789100SFUJITA Tomonori 
2290386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2291773642d9SDouglas Gilbert 		   fake_storep + (block * sdebug_sector_size),
2292773642d9SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, 0, do_write);
2293773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2294a4517511SAkinobu Mita 		return ret;
2295a4517511SAkinobu Mita 
2296a4517511SAkinobu Mita 	if (rest) {
2297386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2298773642d9SDouglas Gilbert 			    fake_storep, rest * sdebug_sector_size,
2299773642d9SDouglas Gilbert 			    (num - rest) * sdebug_sector_size, do_write);
2300a4517511SAkinobu Mita 	}
230119789100SFUJITA Tomonori 
230219789100SFUJITA Tomonori 	return ret;
230319789100SFUJITA Tomonori }
230419789100SFUJITA Tomonori 
230538d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of
230638d5c833SDouglas Gilbert  * arr into fake_store(lba,num) and return true. If comparison fails then
230738d5c833SDouglas Gilbert  * return false. */
2308fd32119bSDouglas Gilbert static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
230938d5c833SDouglas Gilbert {
231038d5c833SDouglas Gilbert 	bool res;
231138d5c833SDouglas Gilbert 	u64 block, rest = 0;
231238d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2313773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
231438d5c833SDouglas Gilbert 
231538d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
231638d5c833SDouglas Gilbert 	if (block + num > store_blks)
231738d5c833SDouglas Gilbert 		rest = block + num - store_blks;
231838d5c833SDouglas Gilbert 
231938d5c833SDouglas Gilbert 	res = !memcmp(fake_storep + (block * lb_size), arr,
232038d5c833SDouglas Gilbert 		      (num - rest) * lb_size);
232138d5c833SDouglas Gilbert 	if (!res)
232238d5c833SDouglas Gilbert 		return res;
232338d5c833SDouglas Gilbert 	if (rest)
232438d5c833SDouglas Gilbert 		res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
232538d5c833SDouglas Gilbert 			     rest * lb_size);
232638d5c833SDouglas Gilbert 	if (!res)
232738d5c833SDouglas Gilbert 		return res;
232838d5c833SDouglas Gilbert 	arr += num * lb_size;
232938d5c833SDouglas Gilbert 	memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
233038d5c833SDouglas Gilbert 	if (rest)
233138d5c833SDouglas Gilbert 		memcpy(fake_storep, arr + ((num - rest) * lb_size),
233238d5c833SDouglas Gilbert 		       rest * lb_size);
233338d5c833SDouglas Gilbert 	return res;
233438d5c833SDouglas Gilbert }
233538d5c833SDouglas Gilbert 
233651d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2337beb40ea4SAkinobu Mita {
233851d648afSAkinobu Mita 	__be16 csum;
2339beb40ea4SAkinobu Mita 
2340773642d9SDouglas Gilbert 	if (sdebug_guard)
234151d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
234251d648afSAkinobu Mita 	else
2343beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
234451d648afSAkinobu Mita 
2345beb40ea4SAkinobu Mita 	return csum;
2346beb40ea4SAkinobu Mita }
2347beb40ea4SAkinobu Mita 
2348beb40ea4SAkinobu Mita static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
2349beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
2350beb40ea4SAkinobu Mita {
2351773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
2352beb40ea4SAkinobu Mita 
2353beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
2354c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
2355beb40ea4SAkinobu Mita 			(unsigned long)sector,
2356beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
2357beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
2358beb40ea4SAkinobu Mita 		return 0x01;
2359beb40ea4SAkinobu Mita 	}
2360773642d9SDouglas Gilbert 	if (sdebug_dif == SD_DIF_TYPE1_PROTECTION &&
2361beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
2362c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2363c1287970STomas Winkler 			(unsigned long)sector);
2364beb40ea4SAkinobu Mita 		return 0x03;
2365beb40ea4SAkinobu Mita 	}
2366773642d9SDouglas Gilbert 	if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
2367beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
2368c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2369c1287970STomas Winkler 			(unsigned long)sector);
2370beb40ea4SAkinobu Mita 		return 0x03;
2371beb40ea4SAkinobu Mita 	}
2372beb40ea4SAkinobu Mita 	return 0;
2373beb40ea4SAkinobu Mita }
2374beb40ea4SAkinobu Mita 
2375bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
237665f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
2377c6a44287SMartin K. Petersen {
2378be4e11beSAkinobu Mita 	size_t resid;
2379c6a44287SMartin K. Petersen 	void *paddr;
238014faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
2381be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
2382c6a44287SMartin K. Petersen 
2383e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
2384e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
2385c6a44287SMartin K. Petersen 
2386be4e11beSAkinobu Mita 	sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2387be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2388be4e11beSAkinobu Mita 			(read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2389be4e11beSAkinobu Mita 
2390be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
2391be4e11beSAkinobu Mita 		size_t len = min(miter.length, resid);
239214faa944SAkinobu Mita 		void *start = dif_store(sector);
2393be4e11beSAkinobu Mita 		size_t rest = 0;
239414faa944SAkinobu Mita 
239514faa944SAkinobu Mita 		if (dif_store_end < start + len)
239614faa944SAkinobu Mita 			rest = start + len - dif_store_end;
2397c6a44287SMartin K. Petersen 
2398be4e11beSAkinobu Mita 		paddr = miter.addr;
239914faa944SAkinobu Mita 
240065f72f2aSAkinobu Mita 		if (read)
240165f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
240265f72f2aSAkinobu Mita 		else
240365f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
240465f72f2aSAkinobu Mita 
240565f72f2aSAkinobu Mita 		if (rest) {
240665f72f2aSAkinobu Mita 			if (read)
240714faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
240865f72f2aSAkinobu Mita 			else
240965f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
241065f72f2aSAkinobu Mita 		}
2411c6a44287SMartin K. Petersen 
2412e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
2413c6a44287SMartin K. Petersen 		resid -= len;
2414c6a44287SMartin K. Petersen 	}
2415be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
2416bb8c063cSAkinobu Mita }
2417c6a44287SMartin K. Petersen 
2418bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2419bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
2420bb8c063cSAkinobu Mita {
2421bb8c063cSAkinobu Mita 	unsigned int i;
2422bb8c063cSAkinobu Mita 	struct sd_dif_tuple *sdt;
2423bb8c063cSAkinobu Mita 	sector_t sector;
2424bb8c063cSAkinobu Mita 
2425c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
2426bb8c063cSAkinobu Mita 		int ret;
2427bb8c063cSAkinobu Mita 
2428bb8c063cSAkinobu Mita 		sector = start_sec + i;
2429bb8c063cSAkinobu Mita 		sdt = dif_store(sector);
2430bb8c063cSAkinobu Mita 
243151d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
2432bb8c063cSAkinobu Mita 			continue;
2433bb8c063cSAkinobu Mita 
2434bb8c063cSAkinobu Mita 		ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2435bb8c063cSAkinobu Mita 		if (ret) {
2436bb8c063cSAkinobu Mita 			dif_errors++;
2437bb8c063cSAkinobu Mita 			return ret;
2438bb8c063cSAkinobu Mita 		}
2439bb8c063cSAkinobu Mita 	}
2440bb8c063cSAkinobu Mita 
244165f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, true);
2442c6a44287SMartin K. Petersen 	dix_reads++;
2443c6a44287SMartin K. Petersen 
2444c6a44287SMartin K. Petersen 	return 0;
2445c6a44287SMartin K. Petersen }
2446c6a44287SMartin K. Petersen 
2447fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
244819789100SFUJITA Tomonori {
2449c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2450c2248fc9SDouglas Gilbert 	u64 lba;
2451c2248fc9SDouglas Gilbert 	u32 num;
2452c2248fc9SDouglas Gilbert 	u32 ei_lba;
245319789100SFUJITA Tomonori 	unsigned long iflags;
245419789100SFUJITA Tomonori 	int ret;
2455c2248fc9SDouglas Gilbert 	bool check_prot;
245619789100SFUJITA Tomonori 
2457c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2458c2248fc9SDouglas Gilbert 	case READ_16:
2459c2248fc9SDouglas Gilbert 		ei_lba = 0;
2460c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2461c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2462c2248fc9SDouglas Gilbert 		check_prot = true;
2463c2248fc9SDouglas Gilbert 		break;
2464c2248fc9SDouglas Gilbert 	case READ_10:
2465c2248fc9SDouglas Gilbert 		ei_lba = 0;
2466c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2467c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2468c2248fc9SDouglas Gilbert 		check_prot = true;
2469c2248fc9SDouglas Gilbert 		break;
2470c2248fc9SDouglas Gilbert 	case READ_6:
2471c2248fc9SDouglas Gilbert 		ei_lba = 0;
2472c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2473c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2474c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2475c2248fc9SDouglas Gilbert 		check_prot = true;
2476c2248fc9SDouglas Gilbert 		break;
2477c2248fc9SDouglas Gilbert 	case READ_12:
2478c2248fc9SDouglas Gilbert 		ei_lba = 0;
2479c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2480c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2481c2248fc9SDouglas Gilbert 		check_prot = true;
2482c2248fc9SDouglas Gilbert 		break;
2483c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
2484c2248fc9SDouglas Gilbert 		ei_lba = 0;
2485c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2486c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2487c2248fc9SDouglas Gilbert 		check_prot = false;
2488c2248fc9SDouglas Gilbert 		break;
2489c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
2490c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2491c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2492c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2493c2248fc9SDouglas Gilbert 		check_prot = false;
2494c2248fc9SDouglas Gilbert 		break;
2495c2248fc9SDouglas Gilbert 	}
2496f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
2497773642d9SDouglas Gilbert 		if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
2498c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2499c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2500c2248fc9SDouglas Gilbert 			return check_condition_result;
2501c2248fc9SDouglas Gilbert 		}
2502773642d9SDouglas Gilbert 		if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2503773642d9SDouglas Gilbert 		     sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
2504c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2505c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2506c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2507c2248fc9SDouglas Gilbert 	}
2508f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
2509c2248fc9SDouglas Gilbert 		struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2510c2248fc9SDouglas Gilbert 
2511c2248fc9SDouglas Gilbert 		if (ep->inj_short)
2512c2248fc9SDouglas Gilbert 			num /= 2;
2513c2248fc9SDouglas Gilbert 	}
2514c2248fc9SDouglas Gilbert 
2515c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2516f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
2517c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2518c2248fc9SDouglas Gilbert 		return check_condition_result;
2519c2248fc9SDouglas Gilbert 	}
2520c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2521f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
2522c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2523c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2524c2248fc9SDouglas Gilbert 		return check_condition_result;
2525c2248fc9SDouglas Gilbert 	}
252619789100SFUJITA Tomonori 
2527f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
252832f7ef73SDouglas Gilbert 		     (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
2529f46eb0e9SDouglas Gilbert 		     ((lba + num) > OPT_MEDIUM_ERR_ADDR))) {
2530c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
2531c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
2532c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
2533c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2534c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
253532f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
253632f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
2537c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
2538c65b1445SDouglas Gilbert 		}
2539c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
25401da177e4SLinus Torvalds 		return check_condition_result;
25411da177e4SLinus Torvalds 	}
2542c6a44287SMartin K. Petersen 
25436c78cc06SAkinobu Mita 	read_lock_irqsave(&atomic_rw, iflags);
25446c78cc06SAkinobu Mita 
2545c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2546f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
2547c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
2548c6a44287SMartin K. Petersen 
2549c6a44287SMartin K. Petersen 		if (prot_ret) {
25506c78cc06SAkinobu Mita 			read_unlock_irqrestore(&atomic_rw, iflags);
2551c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
2552c6a44287SMartin K. Petersen 			return illegal_condition_result;
2553c6a44287SMartin K. Petersen 		}
2554c6a44287SMartin K. Petersen 	}
2555c6a44287SMartin K. Petersen 
2556c2248fc9SDouglas Gilbert 	ret = do_device_access(scp, lba, num, false);
25571da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
2558f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
2559a4517511SAkinobu Mita 		return DID_ERROR << 16;
2560a4517511SAkinobu Mita 
2561c2248fc9SDouglas Gilbert 	scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
2562a4517511SAkinobu Mita 
2563f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
2564c2248fc9SDouglas Gilbert 		struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2565c2248fc9SDouglas Gilbert 
2566c2248fc9SDouglas Gilbert 		if (ep->inj_recovered) {
2567c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
2568c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
2569c2248fc9SDouglas Gilbert 			return check_condition_result;
2570c2248fc9SDouglas Gilbert 		} else if (ep->inj_transport) {
2571c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND,
2572c2248fc9SDouglas Gilbert 					TRANSPORT_PROBLEM, ACK_NAK_TO);
2573c2248fc9SDouglas Gilbert 			return check_condition_result;
2574c2248fc9SDouglas Gilbert 		} else if (ep->inj_dif) {
2575c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
2576c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2577c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2578c2248fc9SDouglas Gilbert 		} else if (ep->inj_dix) {
2579c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2580c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2581c2248fc9SDouglas Gilbert 		}
2582c2248fc9SDouglas Gilbert 	}
2583a4517511SAkinobu Mita 	return 0;
25841da177e4SLinus Torvalds }
25851da177e4SLinus Torvalds 
258658a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len)
2587c6a44287SMartin K. Petersen {
2588cbf67842SDouglas Gilbert 	int i, j, n;
2589c6a44287SMartin K. Petersen 
2590cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
2591c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
2592cbf67842SDouglas Gilbert 		char b[128];
2593c6a44287SMartin K. Petersen 
2594cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
2595c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
2596c6a44287SMartin K. Petersen 
2597cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
2598cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2599cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
2600cbf67842SDouglas Gilbert 			else
2601cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2602cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
2603cbf67842SDouglas Gilbert 		}
2604cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
2605c6a44287SMartin K. Petersen 	}
2606c6a44287SMartin K. Petersen }
2607c6a44287SMartin K. Petersen 
2608c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
2609395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
2610c6a44287SMartin K. Petersen {
2611be4e11beSAkinobu Mita 	int ret;
2612c6a44287SMartin K. Petersen 	struct sd_dif_tuple *sdt;
2613be4e11beSAkinobu Mita 	void *daddr;
261465f72f2aSAkinobu Mita 	sector_t sector = start_sec;
2615c6a44287SMartin K. Petersen 	int ppage_offset;
2616be4e11beSAkinobu Mita 	int dpage_offset;
2617be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
2618be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
2619c6a44287SMartin K. Petersen 
2620c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
2621c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2622c6a44287SMartin K. Petersen 
2623be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2624be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
2625be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2626be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2627be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2628c6a44287SMartin K. Petersen 
2629be4e11beSAkinobu Mita 	/* For each protection page */
2630be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
2631be4e11beSAkinobu Mita 		dpage_offset = 0;
2632be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
2633be4e11beSAkinobu Mita 			ret = 0x01;
2634be4e11beSAkinobu Mita 			goto out;
2635c6a44287SMartin K. Petersen 		}
2636c6a44287SMartin K. Petersen 
2637be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
2638be4e11beSAkinobu Mita 		     ppage_offset += sizeof(struct sd_dif_tuple)) {
2639be4e11beSAkinobu Mita 			/* If we're at the end of the current
2640be4e11beSAkinobu Mita 			 * data page advance to the next one
2641be4e11beSAkinobu Mita 			 */
2642be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
2643be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
2644be4e11beSAkinobu Mita 					ret = 0x01;
2645be4e11beSAkinobu Mita 					goto out;
2646be4e11beSAkinobu Mita 				}
2647be4e11beSAkinobu Mita 				dpage_offset = 0;
2648be4e11beSAkinobu Mita 			}
2649c6a44287SMartin K. Petersen 
2650be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
2651be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
2652be4e11beSAkinobu Mita 
2653be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
2654beb40ea4SAkinobu Mita 			if (ret) {
2655773642d9SDouglas Gilbert 				dump_sector(daddr, sdebug_sector_size);
2656395cef03SMartin K. Petersen 				goto out;
2657395cef03SMartin K. Petersen 			}
2658395cef03SMartin K. Petersen 
2659c6a44287SMartin K. Petersen 			sector++;
2660395cef03SMartin K. Petersen 			ei_lba++;
2661773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
2662c6a44287SMartin K. Petersen 		}
2663be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
2664be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
2665c6a44287SMartin K. Petersen 	}
2666be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2667c6a44287SMartin K. Petersen 
266865f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
2669c6a44287SMartin K. Petersen 	dix_writes++;
2670c6a44287SMartin K. Petersen 
2671c6a44287SMartin K. Petersen 	return 0;
2672c6a44287SMartin K. Petersen 
2673c6a44287SMartin K. Petersen out:
2674c6a44287SMartin K. Petersen 	dif_errors++;
2675be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
2676be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2677c6a44287SMartin K. Petersen 	return ret;
2678c6a44287SMartin K. Petersen }
2679c6a44287SMartin K. Petersen 
2680b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
2681b90ebc3dSAkinobu Mita {
2682773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2683773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2684773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
2685b90ebc3dSAkinobu Mita 	return lba;
2686b90ebc3dSAkinobu Mita }
2687b90ebc3dSAkinobu Mita 
2688b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
2689b90ebc3dSAkinobu Mita {
2690773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
2691a027b5b9SAkinobu Mita 
2692773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2693773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
2694a027b5b9SAkinobu Mita 	return lba;
2695a027b5b9SAkinobu Mita }
2696a027b5b9SAkinobu Mita 
269744d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
269844d92694SMartin K. Petersen {
2699b90ebc3dSAkinobu Mita 	sector_t end;
2700b90ebc3dSAkinobu Mita 	unsigned int mapped;
2701b90ebc3dSAkinobu Mita 	unsigned long index;
2702b90ebc3dSAkinobu Mita 	unsigned long next;
270344d92694SMartin K. Petersen 
2704b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
2705b90ebc3dSAkinobu Mita 	mapped = test_bit(index, map_storep);
270644d92694SMartin K. Petersen 
270744d92694SMartin K. Petersen 	if (mapped)
2708b90ebc3dSAkinobu Mita 		next = find_next_zero_bit(map_storep, map_size, index);
270944d92694SMartin K. Petersen 	else
2710b90ebc3dSAkinobu Mita 		next = find_next_bit(map_storep, map_size, index);
271144d92694SMartin K. Petersen 
2712b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
271344d92694SMartin K. Petersen 	*num = end - lba;
271444d92694SMartin K. Petersen 	return mapped;
271544d92694SMartin K. Petersen }
271644d92694SMartin K. Petersen 
271744d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
271844d92694SMartin K. Petersen {
271944d92694SMartin K. Petersen 	sector_t end = lba + len;
272044d92694SMartin K. Petersen 
272144d92694SMartin K. Petersen 	while (lba < end) {
2722b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
272344d92694SMartin K. Petersen 
2724b90ebc3dSAkinobu Mita 		if (index < map_size)
2725b90ebc3dSAkinobu Mita 			set_bit(index, map_storep);
272644d92694SMartin K. Petersen 
2727b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
272844d92694SMartin K. Petersen 	}
272944d92694SMartin K. Petersen }
273044d92694SMartin K. Petersen 
273144d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
273244d92694SMartin K. Petersen {
273344d92694SMartin K. Petersen 	sector_t end = lba + len;
273444d92694SMartin K. Petersen 
273544d92694SMartin K. Petersen 	while (lba < end) {
2736b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
273744d92694SMartin K. Petersen 
2738b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
2739773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
2740b90ebc3dSAkinobu Mita 		    index < map_size) {
2741b90ebc3dSAkinobu Mita 			clear_bit(index, map_storep);
2742773642d9SDouglas Gilbert 			if (sdebug_lbprz) {
2743be1dd78dSEric Sandeen 				memset(fake_storep +
2744773642d9SDouglas Gilbert 				       lba * sdebug_sector_size, 0,
2745773642d9SDouglas Gilbert 				       sdebug_sector_size *
2746773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2747be1dd78dSEric Sandeen 			}
2748e9926b43SAkinobu Mita 			if (dif_storep) {
2749e9926b43SAkinobu Mita 				memset(dif_storep + lba, 0xff,
2750e9926b43SAkinobu Mita 				       sizeof(*dif_storep) *
2751773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2752e9926b43SAkinobu Mita 			}
2753b90ebc3dSAkinobu Mita 		}
2754b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
275544d92694SMartin K. Petersen 	}
275644d92694SMartin K. Petersen }
275744d92694SMartin K. Petersen 
2758fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
27591da177e4SLinus Torvalds {
2760c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2761c2248fc9SDouglas Gilbert 	u64 lba;
2762c2248fc9SDouglas Gilbert 	u32 num;
2763c2248fc9SDouglas Gilbert 	u32 ei_lba;
27641da177e4SLinus Torvalds 	unsigned long iflags;
276519789100SFUJITA Tomonori 	int ret;
2766c2248fc9SDouglas Gilbert 	bool check_prot;
27671da177e4SLinus Torvalds 
2768c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2769c2248fc9SDouglas Gilbert 	case WRITE_16:
2770c2248fc9SDouglas Gilbert 		ei_lba = 0;
2771c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2772c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2773c2248fc9SDouglas Gilbert 		check_prot = true;
2774c2248fc9SDouglas Gilbert 		break;
2775c2248fc9SDouglas Gilbert 	case WRITE_10:
2776c2248fc9SDouglas Gilbert 		ei_lba = 0;
2777c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2778c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2779c2248fc9SDouglas Gilbert 		check_prot = true;
2780c2248fc9SDouglas Gilbert 		break;
2781c2248fc9SDouglas Gilbert 	case WRITE_6:
2782c2248fc9SDouglas Gilbert 		ei_lba = 0;
2783c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2784c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2785c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2786c2248fc9SDouglas Gilbert 		check_prot = true;
2787c2248fc9SDouglas Gilbert 		break;
2788c2248fc9SDouglas Gilbert 	case WRITE_12:
2789c2248fc9SDouglas Gilbert 		ei_lba = 0;
2790c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2791c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2792c2248fc9SDouglas Gilbert 		check_prot = true;
2793c2248fc9SDouglas Gilbert 		break;
2794c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
2795c2248fc9SDouglas Gilbert 		ei_lba = 0;
2796c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2797c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2798c2248fc9SDouglas Gilbert 		check_prot = false;
2799c2248fc9SDouglas Gilbert 		break;
2800c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
2801c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2802c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2803c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2804c2248fc9SDouglas Gilbert 		check_prot = false;
2805c2248fc9SDouglas Gilbert 		break;
2806c2248fc9SDouglas Gilbert 	}
2807f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
2808773642d9SDouglas Gilbert 		if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
2809c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2810c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2811c2248fc9SDouglas Gilbert 			return check_condition_result;
2812c2248fc9SDouglas Gilbert 		}
2813773642d9SDouglas Gilbert 		if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2814773642d9SDouglas Gilbert 		     sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
2815c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2816c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2817c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2818c2248fc9SDouglas Gilbert 	}
2819c2248fc9SDouglas Gilbert 
2820c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2821f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
2822c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2823c2248fc9SDouglas Gilbert 		return check_condition_result;
2824c2248fc9SDouglas Gilbert 	}
2825c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2826f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
2827c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2828c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2829c2248fc9SDouglas Gilbert 		return check_condition_result;
2830c2248fc9SDouglas Gilbert 	}
28311da177e4SLinus Torvalds 
28326c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
28336c78cc06SAkinobu Mita 
2834c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2835f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
2836c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
2837c6a44287SMartin K. Petersen 
2838c6a44287SMartin K. Petersen 		if (prot_ret) {
28396c78cc06SAkinobu Mita 			write_unlock_irqrestore(&atomic_rw, iflags);
2840c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
2841c6a44287SMartin K. Petersen 			return illegal_condition_result;
2842c6a44287SMartin K. Petersen 		}
2843c6a44287SMartin K. Petersen 	}
2844c6a44287SMartin K. Petersen 
2845c2248fc9SDouglas Gilbert 	ret = do_device_access(scp, lba, num, true);
2846f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
284744d92694SMartin K. Petersen 		map_region(lba, num);
28481da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
2849f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
2850773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2851773642d9SDouglas Gilbert 	else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
2852c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2853cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
2854773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
285544d92694SMartin K. Petersen 
2856f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
2857c2248fc9SDouglas Gilbert 		struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2858c2248fc9SDouglas Gilbert 
2859c2248fc9SDouglas Gilbert 		if (ep->inj_recovered) {
2860c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
2861c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
2862c2248fc9SDouglas Gilbert 			return check_condition_result;
2863c2248fc9SDouglas Gilbert 		} else if (ep->inj_dif) {
2864c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
2865c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2866c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2867c2248fc9SDouglas Gilbert 		} else if (ep->inj_dix) {
2868c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2869c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2870c2248fc9SDouglas Gilbert 		}
2871c2248fc9SDouglas Gilbert 	}
28721da177e4SLinus Torvalds 	return 0;
28731da177e4SLinus Torvalds }
28741da177e4SLinus Torvalds 
2875fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
2876fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
287744d92694SMartin K. Petersen {
287844d92694SMartin K. Petersen 	unsigned long iflags;
287944d92694SMartin K. Petersen 	unsigned long long i;
288044d92694SMartin K. Petersen 	int ret;
2881773642d9SDouglas Gilbert 	u64 lba_off;
288244d92694SMartin K. Petersen 
2883c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num);
288444d92694SMartin K. Petersen 	if (ret)
288544d92694SMartin K. Petersen 		return ret;
288644d92694SMartin K. Petersen 
288744d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
288844d92694SMartin K. Petersen 
28899ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
289044d92694SMartin K. Petersen 		unmap_region(lba, num);
289144d92694SMartin K. Petersen 		goto out;
289244d92694SMartin K. Petersen 	}
289344d92694SMartin K. Petersen 
2894773642d9SDouglas Gilbert 	lba_off = lba * sdebug_sector_size;
2895c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
2896c2248fc9SDouglas Gilbert 	if (ndob) {
2897773642d9SDouglas Gilbert 		memset(fake_storep + lba_off, 0, sdebug_sector_size);
2898c2248fc9SDouglas Gilbert 		ret = 0;
2899c2248fc9SDouglas Gilbert 	} else
2900773642d9SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
2901773642d9SDouglas Gilbert 					  sdebug_sector_size);
290244d92694SMartin K. Petersen 
290344d92694SMartin K. Petersen 	if (-1 == ret) {
290444d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
2905773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2906773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
2907c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2908cbf67842SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
2909cbf67842SDouglas Gilbert 			    my_name, "write same",
2910773642d9SDouglas Gilbert 			    num * sdebug_sector_size, ret);
291144d92694SMartin K. Petersen 
291244d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
291344d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
2914773642d9SDouglas Gilbert 		memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
2915773642d9SDouglas Gilbert 		       fake_storep + lba_off,
2916773642d9SDouglas Gilbert 		       sdebug_sector_size);
291744d92694SMartin K. Petersen 
29189ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
291944d92694SMartin K. Petersen 		map_region(lba, num);
292044d92694SMartin K. Petersen out:
292144d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
292244d92694SMartin K. Petersen 
292344d92694SMartin K. Petersen 	return 0;
292444d92694SMartin K. Petersen }
292544d92694SMartin K. Petersen 
2926fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
2927fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
2928c2248fc9SDouglas Gilbert {
2929c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2930c2248fc9SDouglas Gilbert 	u32 lba;
2931c2248fc9SDouglas Gilbert 	u16 num;
2932c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
2933c2248fc9SDouglas Gilbert 	bool unmap = false;
2934c2248fc9SDouglas Gilbert 
2935c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
2936773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
2937c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
2938c2248fc9SDouglas Gilbert 			return check_condition_result;
2939c2248fc9SDouglas Gilbert 		} else
2940c2248fc9SDouglas Gilbert 			unmap = true;
2941c2248fc9SDouglas Gilbert 	}
2942c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
2943c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
2944773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
2945c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
2946c2248fc9SDouglas Gilbert 		return check_condition_result;
2947c2248fc9SDouglas Gilbert 	}
2948c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
2949c2248fc9SDouglas Gilbert }
2950c2248fc9SDouglas Gilbert 
2951fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
2952fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
2953c2248fc9SDouglas Gilbert {
2954c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2955c2248fc9SDouglas Gilbert 	u64 lba;
2956c2248fc9SDouglas Gilbert 	u32 num;
2957c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
2958c2248fc9SDouglas Gilbert 	bool unmap = false;
2959c2248fc9SDouglas Gilbert 	bool ndob = false;
2960c2248fc9SDouglas Gilbert 
2961c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
2962773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
2963c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
2964c2248fc9SDouglas Gilbert 			return check_condition_result;
2965c2248fc9SDouglas Gilbert 		} else
2966c2248fc9SDouglas Gilbert 			unmap = true;
2967c2248fc9SDouglas Gilbert 	}
2968c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
2969c2248fc9SDouglas Gilbert 		ndob = true;
2970c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
2971c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
2972773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
2973c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
2974c2248fc9SDouglas Gilbert 		return check_condition_result;
2975c2248fc9SDouglas Gilbert 	}
2976c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
2977c2248fc9SDouglas Gilbert }
2978c2248fc9SDouglas Gilbert 
2979acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
2980acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
2981acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
2982fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
2983fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
2984acafd0b9SEwan D. Milne {
2985acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
2986acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
2987acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
2988acafd0b9SEwan D. Milne 	u8 mode;
2989acafd0b9SEwan D. Milne 
2990acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
2991acafd0b9SEwan D. Milne 	switch (mode) {
2992acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
2993acafd0b9SEwan D. Milne 		/* set UAs on this device only */
2994acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
2995acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
2996acafd0b9SEwan D. Milne 		break;
2997acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
2998acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
2999acafd0b9SEwan D. Milne 		break;
3000acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3001acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3002acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3003acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3004acafd0b9SEwan D. Milne 				    dev_list)
3005acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3006acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3007acafd0b9SEwan D. Milne 				if (devip != dp)
3008acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3009acafd0b9SEwan D. Milne 						dp->uas_bm);
3010acafd0b9SEwan D. Milne 			}
3011acafd0b9SEwan D. Milne 		break;
3012acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3013acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3014acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3015acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3016acafd0b9SEwan D. Milne 				    dev_list)
3017acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3018acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3019acafd0b9SEwan D. Milne 					dp->uas_bm);
3020acafd0b9SEwan D. Milne 		break;
3021acafd0b9SEwan D. Milne 	default:
3022acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3023acafd0b9SEwan D. Milne 		break;
3024acafd0b9SEwan D. Milne 	}
3025acafd0b9SEwan D. Milne 	return 0;
3026acafd0b9SEwan D. Milne }
3027acafd0b9SEwan D. Milne 
3028fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3029fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
303038d5c833SDouglas Gilbert {
303138d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
303238d5c833SDouglas Gilbert 	u8 *arr;
303338d5c833SDouglas Gilbert 	u8 *fake_storep_hold;
303438d5c833SDouglas Gilbert 	u64 lba;
303538d5c833SDouglas Gilbert 	u32 dnum;
3036773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
303738d5c833SDouglas Gilbert 	u8 num;
303838d5c833SDouglas Gilbert 	unsigned long iflags;
303938d5c833SDouglas Gilbert 	int ret;
3040d467d31fSDouglas Gilbert 	int retval = 0;
304138d5c833SDouglas Gilbert 
3042d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
304338d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
304438d5c833SDouglas Gilbert 	if (0 == num)
304538d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
3046773642d9SDouglas Gilbert 	if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
304738d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
304838d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
304938d5c833SDouglas Gilbert 		return check_condition_result;
305038d5c833SDouglas Gilbert 	}
3051773642d9SDouglas Gilbert 	if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
3052773642d9SDouglas Gilbert 	     sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
305338d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
305438d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
305538d5c833SDouglas Gilbert 			    "to DIF device\n");
305638d5c833SDouglas Gilbert 
305738d5c833SDouglas Gilbert 	/* inline check_device_access_params() */
305838d5c833SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
305938d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
306038d5c833SDouglas Gilbert 		return check_condition_result;
306138d5c833SDouglas Gilbert 	}
306238d5c833SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
306338d5c833SDouglas Gilbert 	if (num > sdebug_store_sectors) {
306438d5c833SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
306538d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
306638d5c833SDouglas Gilbert 		return check_condition_result;
306738d5c833SDouglas Gilbert 	}
3068d467d31fSDouglas Gilbert 	dnum = 2 * num;
3069d467d31fSDouglas Gilbert 	arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3070d467d31fSDouglas Gilbert 	if (NULL == arr) {
3071d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3072d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3073d467d31fSDouglas Gilbert 		return check_condition_result;
3074d467d31fSDouglas Gilbert 	}
307538d5c833SDouglas Gilbert 
307638d5c833SDouglas Gilbert 	write_lock_irqsave(&atomic_rw, iflags);
307738d5c833SDouglas Gilbert 
307838d5c833SDouglas Gilbert 	/* trick do_device_access() to fetch both compare and write buffers
307938d5c833SDouglas Gilbert 	 * from data-in into arr. Safe (atomic) since write_lock held. */
308038d5c833SDouglas Gilbert 	fake_storep_hold = fake_storep;
308138d5c833SDouglas Gilbert 	fake_storep = arr;
308238d5c833SDouglas Gilbert 	ret = do_device_access(scp, 0, dnum, true);
308338d5c833SDouglas Gilbert 	fake_storep = fake_storep_hold;
308438d5c833SDouglas Gilbert 	if (ret == -1) {
3085d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3086d467d31fSDouglas Gilbert 		goto cleanup;
3087773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
308838d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
308938d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
309038d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
309138d5c833SDouglas Gilbert 	if (!comp_write_worker(lba, num, arr)) {
309238d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3093d467d31fSDouglas Gilbert 		retval = check_condition_result;
3094d467d31fSDouglas Gilbert 		goto cleanup;
309538d5c833SDouglas Gilbert 	}
309638d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
309738d5c833SDouglas Gilbert 		map_region(lba, num);
3098d467d31fSDouglas Gilbert cleanup:
309938d5c833SDouglas Gilbert 	write_unlock_irqrestore(&atomic_rw, iflags);
3100d467d31fSDouglas Gilbert 	kfree(arr);
3101d467d31fSDouglas Gilbert 	return retval;
310238d5c833SDouglas Gilbert }
310338d5c833SDouglas Gilbert 
310444d92694SMartin K. Petersen struct unmap_block_desc {
310544d92694SMartin K. Petersen 	__be64	lba;
310644d92694SMartin K. Petersen 	__be32	blocks;
310744d92694SMartin K. Petersen 	__be32	__reserved;
310844d92694SMartin K. Petersen };
310944d92694SMartin K. Petersen 
3110fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
311144d92694SMartin K. Petersen {
311244d92694SMartin K. Petersen 	unsigned char *buf;
311344d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
311444d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
311544d92694SMartin K. Petersen 	int ret;
31166c78cc06SAkinobu Mita 	unsigned long iflags;
311744d92694SMartin K. Petersen 
311844d92694SMartin K. Petersen 
3119c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3120c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3121c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3122c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
312344d92694SMartin K. Petersen 
312444d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3125773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3126c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
312744d92694SMartin K. Petersen 		return check_condition_result;
3128c2248fc9SDouglas Gilbert 	}
312944d92694SMartin K. Petersen 
3130b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3131c2248fc9SDouglas Gilbert 	if (!buf) {
3132c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3133c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3134c2248fc9SDouglas Gilbert 		return check_condition_result;
3135c2248fc9SDouglas Gilbert 	}
3136c2248fc9SDouglas Gilbert 
3137c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
313844d92694SMartin K. Petersen 
313944d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
314044d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
314144d92694SMartin K. Petersen 
314244d92694SMartin K. Petersen 	desc = (void *)&buf[8];
314344d92694SMartin K. Petersen 
31446c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
31456c78cc06SAkinobu Mita 
314644d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
314744d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
314844d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
314944d92694SMartin K. Petersen 
3150c2248fc9SDouglas Gilbert 		ret = check_device_access_params(scp, lba, num);
315144d92694SMartin K. Petersen 		if (ret)
315244d92694SMartin K. Petersen 			goto out;
315344d92694SMartin K. Petersen 
315444d92694SMartin K. Petersen 		unmap_region(lba, num);
315544d92694SMartin K. Petersen 	}
315644d92694SMartin K. Petersen 
315744d92694SMartin K. Petersen 	ret = 0;
315844d92694SMartin K. Petersen 
315944d92694SMartin K. Petersen out:
31606c78cc06SAkinobu Mita 	write_unlock_irqrestore(&atomic_rw, iflags);
316144d92694SMartin K. Petersen 	kfree(buf);
316244d92694SMartin K. Petersen 
316344d92694SMartin K. Petersen 	return ret;
316444d92694SMartin K. Petersen }
316544d92694SMartin K. Petersen 
316644d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
316744d92694SMartin K. Petersen 
3168fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
3169fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
317044d92694SMartin K. Petersen {
3171c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3172c2248fc9SDouglas Gilbert 	u64 lba;
3173c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
3174c2248fc9SDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
317544d92694SMartin K. Petersen 	int ret;
317644d92694SMartin K. Petersen 
3177c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3178c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
317944d92694SMartin K. Petersen 
318044d92694SMartin K. Petersen 	if (alloc_len < 24)
318144d92694SMartin K. Petersen 		return 0;
318244d92694SMartin K. Petersen 
3183c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, 1);
318444d92694SMartin K. Petersen 	if (ret)
318544d92694SMartin K. Petersen 		return ret;
318644d92694SMartin K. Petersen 
3187c2248fc9SDouglas Gilbert 	if (scsi_debug_lbp())
318844d92694SMartin K. Petersen 		mapped = map_state(lba, &num);
3189c2248fc9SDouglas Gilbert 	else {
3190c2248fc9SDouglas Gilbert 		mapped = 1;
3191c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
3192c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
3193c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
3194c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
3195c2248fc9SDouglas Gilbert 		else
3196c2248fc9SDouglas Gilbert 			num = 0xffffffff;
3197c2248fc9SDouglas Gilbert 	}
319844d92694SMartin K. Petersen 
319944d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
3200c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
3201c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
3202c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
3203c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
320444d92694SMartin K. Petersen 
3205c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
320644d92694SMartin K. Petersen }
320744d92694SMartin K. Petersen 
3208c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256
32091da177e4SLinus Torvalds 
32101da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp,
32111da177e4SLinus Torvalds 			    struct sdebug_dev_info * devip)
32121da177e4SLinus Torvalds {
32131da177e4SLinus Torvalds 	unsigned int alloc_len;
321422017ed2SDouglas Gilbert 	int lun_cnt, i, upper, num, n, want_wlun, shortish;
321522017ed2SDouglas Gilbert 	u64 lun;
321601123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
32171da177e4SLinus Torvalds 	int select_report = (int)cmd[2];
32181da177e4SLinus Torvalds 	struct scsi_lun *one_lun;
32191da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_RLUN_ARR_SZ];
3220c65b1445SDouglas Gilbert 	unsigned char * max_addr;
32211da177e4SLinus Torvalds 
322219c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
32231da177e4SLinus Torvalds 	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
322422017ed2SDouglas Gilbert 	shortish = (alloc_len < 4);
322522017ed2SDouglas Gilbert 	if (shortish || (select_report > 2)) {
322622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, shortish ? 6 : 2, -1);
32271da177e4SLinus Torvalds 		return check_condition_result;
32281da177e4SLinus Torvalds 	}
32291da177e4SLinus Torvalds 	/* can produce response with up to 16k luns (lun 0 to lun 16383) */
32301da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
3231773642d9SDouglas Gilbert 	lun_cnt = sdebug_max_luns;
3232c65b1445SDouglas Gilbert 	if (1 == select_report)
3233c65b1445SDouglas Gilbert 		lun_cnt = 0;
3234773642d9SDouglas Gilbert 	else if (sdebug_no_lun_0 && (lun_cnt > 0))
3235c65b1445SDouglas Gilbert 		--lun_cnt;
323622017ed2SDouglas Gilbert 	want_wlun = (select_report > 0) ? 1 : 0;
323722017ed2SDouglas Gilbert 	num = lun_cnt + want_wlun;
3238c65b1445SDouglas Gilbert 	arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
3239c65b1445SDouglas Gilbert 	arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
3240c65b1445SDouglas Gilbert 	n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
3241c65b1445SDouglas Gilbert 			    sizeof(struct scsi_lun)), num);
3242c65b1445SDouglas Gilbert 	if (n < num) {
324322017ed2SDouglas Gilbert 		want_wlun = 0;
3244c65b1445SDouglas Gilbert 		lun_cnt = n;
3245c65b1445SDouglas Gilbert 	}
32461da177e4SLinus Torvalds 	one_lun = (struct scsi_lun *) &arr[8];
3247c65b1445SDouglas Gilbert 	max_addr = arr + SDEBUG_RLUN_ARR_SZ;
3248773642d9SDouglas Gilbert 	for (i = 0, lun = (sdebug_no_lun_0 ? 1 : 0);
3249c65b1445SDouglas Gilbert              ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
3250c65b1445SDouglas Gilbert 	     i++, lun++) {
3251c65b1445SDouglas Gilbert 		upper = (lun >> 8) & 0x3f;
32521da177e4SLinus Torvalds 		if (upper)
32531da177e4SLinus Torvalds 			one_lun[i].scsi_lun[0] =
32541da177e4SLinus Torvalds 			    (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
3255c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = lun & 0xff;
32561da177e4SLinus Torvalds 	}
325722017ed2SDouglas Gilbert 	if (want_wlun) {
325834d55434STomas Winkler 		one_lun[i].scsi_lun[0] = (SCSI_W_LUN_REPORT_LUNS >> 8) & 0xff;
325934d55434STomas Winkler 		one_lun[i].scsi_lun[1] = SCSI_W_LUN_REPORT_LUNS & 0xff;
3260c65b1445SDouglas Gilbert 		i++;
3261c65b1445SDouglas Gilbert 	}
3262c65b1445SDouglas Gilbert 	alloc_len = (unsigned char *)(one_lun + i) - arr;
32631da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr,
32641da177e4SLinus Torvalds 				    min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
32651da177e4SLinus Torvalds }
32661da177e4SLinus Torvalds 
3267c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3268c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
3269c639d14eSFUJITA Tomonori {
3270be4e11beSAkinobu Mita 	int j;
3271c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
3272c639d14eSFUJITA Tomonori 	unsigned int offset;
3273c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
3274be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3275c639d14eSFUJITA Tomonori 
3276c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
3277b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3278c5af0db9SAkinobu Mita 	if (!buf) {
327922017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
328022017ed2SDouglas Gilbert 				INSUFF_RES_ASCQ);
3281c5af0db9SAkinobu Mita 		return check_condition_result;
3282c5af0db9SAkinobu Mita 	}
3283c639d14eSFUJITA Tomonori 
328421a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
3285c639d14eSFUJITA Tomonori 
3286c639d14eSFUJITA Tomonori 	offset = 0;
3287be4e11beSAkinobu Mita 	sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3288be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_TO_SG);
3289c639d14eSFUJITA Tomonori 
3290be4e11beSAkinobu Mita 	while (sg_miter_next(&miter)) {
3291be4e11beSAkinobu Mita 		kaddr = miter.addr;
3292be4e11beSAkinobu Mita 		for (j = 0; j < miter.length; j++)
3293be4e11beSAkinobu Mita 			*(kaddr + j) ^= *(buf + offset + j);
3294c639d14eSFUJITA Tomonori 
3295be4e11beSAkinobu Mita 		offset += miter.length;
3296c639d14eSFUJITA Tomonori 	}
3297be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3298c639d14eSFUJITA Tomonori 	kfree(buf);
3299c639d14eSFUJITA Tomonori 
3300be4e11beSAkinobu Mita 	return 0;
3301c639d14eSFUJITA Tomonori }
3302c639d14eSFUJITA Tomonori 
3303fd32119bSDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3304fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
3305c2248fc9SDouglas Gilbert {
3306c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3307c2248fc9SDouglas Gilbert 	u64 lba;
3308c2248fc9SDouglas Gilbert 	u32 num;
3309c2248fc9SDouglas Gilbert 	int errsts;
3310c2248fc9SDouglas Gilbert 
3311c2248fc9SDouglas Gilbert 	if (!scsi_bidi_cmnd(scp)) {
3312c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3313c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3314c2248fc9SDouglas Gilbert 		return check_condition_result;
3315c2248fc9SDouglas Gilbert 	}
3316c2248fc9SDouglas Gilbert 	errsts = resp_read_dt0(scp, devip);
3317c2248fc9SDouglas Gilbert 	if (errsts)
3318c2248fc9SDouglas Gilbert 		return errsts;
3319c2248fc9SDouglas Gilbert 	if (!(cmd[1] & 0x4)) {		/* DISABLE_WRITE is not set */
3320c2248fc9SDouglas Gilbert 		errsts = resp_write_dt0(scp, devip);
3321c2248fc9SDouglas Gilbert 		if (errsts)
3322c2248fc9SDouglas Gilbert 			return errsts;
3323c2248fc9SDouglas Gilbert 	}
3324c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3325c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3326c2248fc9SDouglas Gilbert 	return resp_xdwriteread(scp, lba, num, devip);
3327c2248fc9SDouglas Gilbert }
3328c2248fc9SDouglas Gilbert 
3329a10bc12aSDouglas Gilbert /* Queued command completions converge here. */
3330fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
33311da177e4SLinus Torvalds {
3332cbf67842SDouglas Gilbert 	int qa_indx;
3333cbf67842SDouglas Gilbert 	int retiring = 0;
33341da177e4SLinus Torvalds 	unsigned long iflags;
3335cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3336cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
3337cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
33381da177e4SLinus Torvalds 
3339cbf67842SDouglas Gilbert 	atomic_inc(&sdebug_completions);
3340a10bc12aSDouglas Gilbert 	qa_indx = sd_dp->qa_indx;
3341f46eb0e9SDouglas Gilbert 	if (unlikely((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE))) {
3342c1287970STomas Winkler 		pr_err("wild qa_indx=%d\n", qa_indx);
33431da177e4SLinus Torvalds 		return;
33441da177e4SLinus Torvalds 	}
33451da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
3346cbf67842SDouglas Gilbert 	sqcp = &queued_arr[qa_indx];
3347cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
3348f46eb0e9SDouglas Gilbert 	if (unlikely(NULL == scp)) {
33491da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
3350c1287970STomas Winkler 		pr_err("scp is NULL\n");
33511da177e4SLinus Torvalds 		return;
33521da177e4SLinus Torvalds 	}
3353cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
3354f46eb0e9SDouglas Gilbert 	if (likely(devip))
3355cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
3356cbf67842SDouglas Gilbert 	else
3357c1287970STomas Winkler 		pr_err("devip=NULL\n");
3358f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
3359cbf67842SDouglas Gilbert 		retiring = 1;
3360cbf67842SDouglas Gilbert 
3361cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
3362f46eb0e9SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qa_indx, queued_in_use_bm))) {
33631da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
3364c1287970STomas Winkler 		pr_err("Unexpected completion\n");
3365cbf67842SDouglas Gilbert 		return;
33661da177e4SLinus Torvalds 	}
33671da177e4SLinus Torvalds 
3368cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
3369cbf67842SDouglas Gilbert 		int k, retval;
3370cbf67842SDouglas Gilbert 
3371cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
3372cbf67842SDouglas Gilbert 		if (qa_indx >= retval) {
3373cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
3374c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
3375cbf67842SDouglas Gilbert 			return;
3376cbf67842SDouglas Gilbert 		}
3377cbf67842SDouglas Gilbert 		k = find_last_bit(queued_in_use_bm, retval);
3378773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
3379cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3380cbf67842SDouglas Gilbert 		else
3381cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
3382cbf67842SDouglas Gilbert 	}
3383cbf67842SDouglas Gilbert 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
3384cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
3385cbf67842SDouglas Gilbert }
3386cbf67842SDouglas Gilbert 
3387cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
3388fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
3389cbf67842SDouglas Gilbert {
3390a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3391a10bc12aSDouglas Gilbert 						  hrt);
3392a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3393cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
3394cbf67842SDouglas Gilbert }
33951da177e4SLinus Torvalds 
3396a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
3397fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
3398a10bc12aSDouglas Gilbert {
3399a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3400a10bc12aSDouglas Gilbert 						  ew.work);
3401a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3402a10bc12aSDouglas Gilbert }
3403a10bc12aSDouglas Gilbert 
3404fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
3405fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
34065cb2fc06SFUJITA Tomonori {
34075cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
34085cb2fc06SFUJITA Tomonori 
34095cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
34105cb2fc06SFUJITA Tomonori 	if (devip) {
34115cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
34125cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
34135cb2fc06SFUJITA Tomonori 	}
34145cb2fc06SFUJITA Tomonori 	return devip;
34155cb2fc06SFUJITA Tomonori }
34165cb2fc06SFUJITA Tomonori 
3417f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
34181da177e4SLinus Torvalds {
34191da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
34201da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
3421f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
34221da177e4SLinus Torvalds 
3423d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
34241da177e4SLinus Torvalds 	if (!sdbg_host) {
3425c1287970STomas Winkler 		pr_err("Host info NULL\n");
34261da177e4SLinus Torvalds 		return NULL;
34271da177e4SLinus Torvalds         }
34281da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
34291da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
34301da177e4SLinus Torvalds                     (devip->target == sdev->id) &&
34311da177e4SLinus Torvalds                     (devip->lun == sdev->lun))
34321da177e4SLinus Torvalds                         return devip;
34331da177e4SLinus Torvalds 		else {
34341da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
34351da177e4SLinus Torvalds 				open_devip = devip;
34361da177e4SLinus Torvalds 		}
34371da177e4SLinus Torvalds 	}
34385cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
34395cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
34405cb2fc06SFUJITA Tomonori 		if (!open_devip) {
3441c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
34421da177e4SLinus Torvalds 			return NULL;
34431da177e4SLinus Torvalds 		}
34441da177e4SLinus Torvalds 	}
3445a75869d1SFUJITA Tomonori 
34461da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
34471da177e4SLinus Torvalds 	open_devip->target = sdev->id;
34481da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
34491da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
3450cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
3451cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
3452c2248fc9SDouglas Gilbert 	open_devip->used = true;
34531da177e4SLinus Torvalds 	return open_devip;
34541da177e4SLinus Torvalds }
34551da177e4SLinus Torvalds 
34568dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
34571da177e4SLinus Torvalds {
3458773642d9SDouglas Gilbert 	if (sdebug_verbose)
3459c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
34608dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
346175ad23bcSNick Piggin 	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
34628dea0d02SFUJITA Tomonori 	return 0;
34638dea0d02SFUJITA Tomonori }
34641da177e4SLinus Torvalds 
34658dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
34668dea0d02SFUJITA Tomonori {
3467f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
3468f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
3469a34c4e98SFUJITA Tomonori 
3470773642d9SDouglas Gilbert 	if (sdebug_verbose)
3471c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
34728dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
34738dea0d02SFUJITA Tomonori 	if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
34748dea0d02SFUJITA Tomonori 		sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
3475f46eb0e9SDouglas Gilbert 	if (NULL == devip) {
3476f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
34778dea0d02SFUJITA Tomonori 		if (NULL == devip)
34788dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
3479f46eb0e9SDouglas Gilbert 	}
3480c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
34816bb5e6e7SAkinobu Mita 	blk_queue_max_segment_size(sdp->request_queue, -1U);
3482773642d9SDouglas Gilbert 	if (sdebug_no_uld)
348378d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
34848dea0d02SFUJITA Tomonori 	return 0;
34858dea0d02SFUJITA Tomonori }
34868dea0d02SFUJITA Tomonori 
34878dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
34888dea0d02SFUJITA Tomonori {
34898dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
34908dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
34918dea0d02SFUJITA Tomonori 
3492773642d9SDouglas Gilbert 	if (sdebug_verbose)
3493c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
34948dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
34958dea0d02SFUJITA Tomonori 	if (devip) {
349625985edcSLucas De Marchi 		/* make this slot available for re-use */
3497c2248fc9SDouglas Gilbert 		devip->used = false;
34988dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
34998dea0d02SFUJITA Tomonori 	}
35008dea0d02SFUJITA Tomonori }
35018dea0d02SFUJITA Tomonori 
3502a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
3503a10bc12aSDouglas Gilbert    returns false */
3504a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
35058dea0d02SFUJITA Tomonori {
35068dea0d02SFUJITA Tomonori 	unsigned long iflags;
3507cbf67842SDouglas Gilbert 	int k, qmax, r_qmax;
35088dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3509cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3510a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
35118dea0d02SFUJITA Tomonori 
35128dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
3513773642d9SDouglas Gilbert 	qmax = sdebug_max_queue;
3514cbf67842SDouglas Gilbert 	r_qmax = atomic_read(&retired_max_queue);
3515cbf67842SDouglas Gilbert 	if (r_qmax > qmax)
3516cbf67842SDouglas Gilbert 		qmax = r_qmax;
3517cbf67842SDouglas Gilbert 	for (k = 0; k < qmax; ++k) {
3518cbf67842SDouglas Gilbert 		if (test_bit(k, queued_in_use_bm)) {
35198dea0d02SFUJITA Tomonori 			sqcp = &queued_arr[k];
3520a10bc12aSDouglas Gilbert 			if (cmnd != sqcp->a_cmnd)
3521a10bc12aSDouglas Gilbert 				continue;
3522a10bc12aSDouglas Gilbert 			/* found command */
3523db525fceSDouglas Gilbert 			devip = (struct sdebug_dev_info *)
3524db525fceSDouglas Gilbert 				cmnd->device->hostdata;
3525db525fceSDouglas Gilbert 			if (devip)
3526db525fceSDouglas Gilbert 				atomic_dec(&devip->num_in_q);
3527db525fceSDouglas Gilbert 			sqcp->a_cmnd = NULL;
3528a10bc12aSDouglas Gilbert 			sd_dp = sqcp->sd_dp;
3529db525fceSDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock,
3530db525fceSDouglas Gilbert 					       iflags);
3531a10bc12aSDouglas Gilbert 			if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0)) {
3532a10bc12aSDouglas Gilbert 				if (sd_dp)
3533a10bc12aSDouglas Gilbert 					hrtimer_cancel(&sd_dp->hrt);
3534c2206098SDouglas Gilbert 			} else if (sdebug_jdelay < 0) {
3535a10bc12aSDouglas Gilbert 				if (sd_dp)
3536a10bc12aSDouglas Gilbert 					cancel_work_sync(&sd_dp->ew.work);
3537cbf67842SDouglas Gilbert 			}
3538db525fceSDouglas Gilbert 			clear_bit(k, queued_in_use_bm);
3539a10bc12aSDouglas Gilbert 			return true;
35408dea0d02SFUJITA Tomonori 		}
3541cbf67842SDouglas Gilbert 	}
35428dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
3543a10bc12aSDouglas Gilbert 	return false;
35448dea0d02SFUJITA Tomonori }
35458dea0d02SFUJITA Tomonori 
3546a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
35478dea0d02SFUJITA Tomonori static void stop_all_queued(void)
35488dea0d02SFUJITA Tomonori {
35498dea0d02SFUJITA Tomonori 	unsigned long iflags;
35508dea0d02SFUJITA Tomonori 	int k;
35518dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3552cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3553a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
35548dea0d02SFUJITA Tomonori 
35558dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
3556cbf67842SDouglas Gilbert 	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3557cbf67842SDouglas Gilbert 		if (test_bit(k, queued_in_use_bm)) {
35588dea0d02SFUJITA Tomonori 			sqcp = &queued_arr[k];
3559a10bc12aSDouglas Gilbert 			if (NULL == sqcp->a_cmnd)
3560a10bc12aSDouglas Gilbert 				continue;
3561db525fceSDouglas Gilbert 			devip = (struct sdebug_dev_info *)
3562db525fceSDouglas Gilbert 				sqcp->a_cmnd->device->hostdata;
3563db525fceSDouglas Gilbert 			if (devip)
3564db525fceSDouglas Gilbert 				atomic_dec(&devip->num_in_q);
3565db525fceSDouglas Gilbert 			sqcp->a_cmnd = NULL;
3566a10bc12aSDouglas Gilbert 			sd_dp = sqcp->sd_dp;
3567a10bc12aSDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
3568a10bc12aSDouglas Gilbert 			if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0)) {
3569a10bc12aSDouglas Gilbert 				if (sd_dp)
3570a10bc12aSDouglas Gilbert 					hrtimer_cancel(&sd_dp->hrt);
3571c2206098SDouglas Gilbert 			} else if (sdebug_jdelay < 0) {
3572a10bc12aSDouglas Gilbert 				if (sd_dp)
3573a10bc12aSDouglas Gilbert 					cancel_work_sync(&sd_dp->ew.work);
3574cbf67842SDouglas Gilbert 			}
3575db525fceSDouglas Gilbert 			clear_bit(k, queued_in_use_bm);
3576db525fceSDouglas Gilbert 			spin_lock_irqsave(&queued_arr_lock, iflags);
35778dea0d02SFUJITA Tomonori 		}
35788dea0d02SFUJITA Tomonori 	}
3579cbf67842SDouglas Gilbert 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
3580cbf67842SDouglas Gilbert }
3581cbf67842SDouglas Gilbert 
3582cbf67842SDouglas Gilbert /* Free queued command memory on heap */
3583cbf67842SDouglas Gilbert static void free_all_queued(void)
3584cbf67842SDouglas Gilbert {
3585cbf67842SDouglas Gilbert 	int k;
3586cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3587cbf67842SDouglas Gilbert 
3588cbf67842SDouglas Gilbert 	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3589cbf67842SDouglas Gilbert 		sqcp = &queued_arr[k];
3590a10bc12aSDouglas Gilbert 		kfree(sqcp->sd_dp);
3591a10bc12aSDouglas Gilbert 		sqcp->sd_dp = NULL;
3592cbf67842SDouglas Gilbert 	}
35931da177e4SLinus Torvalds }
35941da177e4SLinus Torvalds 
35951da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
35961da177e4SLinus Torvalds {
3597a10bc12aSDouglas Gilbert 	bool ok;
3598a10bc12aSDouglas Gilbert 
35991da177e4SLinus Torvalds 	++num_aborts;
3600cbf67842SDouglas Gilbert 	if (SCpnt) {
3601a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
3602a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3603a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
3604a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
3605a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
3606cbf67842SDouglas Gilbert 	}
36071da177e4SLinus Torvalds 	return SUCCESS;
36081da177e4SLinus Torvalds }
36091da177e4SLinus Torvalds 
36101da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
36111da177e4SLinus Torvalds {
36121da177e4SLinus Torvalds 	++num_dev_resets;
3613cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
3614cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
3615f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
3616f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
3617cbf67842SDouglas Gilbert 
3618773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3619cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
36201da177e4SLinus Torvalds 		if (devip)
3621cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
36221da177e4SLinus Torvalds 	}
36231da177e4SLinus Torvalds 	return SUCCESS;
36241da177e4SLinus Torvalds }
36251da177e4SLinus Torvalds 
3626cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3627cbf67842SDouglas Gilbert {
3628cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
3629cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3630cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
3631cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
3632cbf67842SDouglas Gilbert 	int k = 0;
3633cbf67842SDouglas Gilbert 
3634cbf67842SDouglas Gilbert 	++num_target_resets;
3635cbf67842SDouglas Gilbert 	if (!SCpnt)
3636cbf67842SDouglas Gilbert 		goto lie;
3637cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
3638cbf67842SDouglas Gilbert 	if (!sdp)
3639cbf67842SDouglas Gilbert 		goto lie;
3640773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3641cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3642cbf67842SDouglas Gilbert 	hp = sdp->host;
3643cbf67842SDouglas Gilbert 	if (!hp)
3644cbf67842SDouglas Gilbert 		goto lie;
3645cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3646cbf67842SDouglas Gilbert 	if (sdbg_host) {
3647cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
3648cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
3649cbf67842SDouglas Gilbert 				    dev_list)
3650cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
3651cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3652cbf67842SDouglas Gilbert 				++k;
3653cbf67842SDouglas Gilbert 			}
3654cbf67842SDouglas Gilbert 	}
3655773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3656cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3657cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
3658cbf67842SDouglas Gilbert lie:
3659cbf67842SDouglas Gilbert 	return SUCCESS;
3660cbf67842SDouglas Gilbert }
3661cbf67842SDouglas Gilbert 
36621da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
36631da177e4SLinus Torvalds {
36641da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
3665cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
36661da177e4SLinus Torvalds         struct scsi_device * sdp;
36671da177e4SLinus Torvalds         struct Scsi_Host * hp;
3668cbf67842SDouglas Gilbert 	int k = 0;
36691da177e4SLinus Torvalds 
36701da177e4SLinus Torvalds 	++num_bus_resets;
3671cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
3672cbf67842SDouglas Gilbert 		goto lie;
3673cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
3674773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3675cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3676cbf67842SDouglas Gilbert 	hp = sdp->host;
3677cbf67842SDouglas Gilbert 	if (hp) {
3678d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
36791da177e4SLinus Torvalds 		if (sdbg_host) {
3680cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
36811da177e4SLinus Torvalds                                             &sdbg_host->dev_info_list,
3682cbf67842SDouglas Gilbert 					    dev_list) {
3683cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3684cbf67842SDouglas Gilbert 				++k;
36851da177e4SLinus Torvalds 			}
36861da177e4SLinus Torvalds 		}
3687cbf67842SDouglas Gilbert 	}
3688773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3689cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3690cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
3691cbf67842SDouglas Gilbert lie:
36921da177e4SLinus Torvalds 	return SUCCESS;
36931da177e4SLinus Torvalds }
36941da177e4SLinus Torvalds 
36951da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
36961da177e4SLinus Torvalds {
36971da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
3698cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3699cbf67842SDouglas Gilbert 	int k = 0;
37001da177e4SLinus Torvalds 
37011da177e4SLinus Torvalds 	++num_host_resets;
3702773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3703cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
37041da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
37051da177e4SLinus Torvalds         list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3706cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
3707cbf67842SDouglas Gilbert 				    dev_list) {
3708cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3709cbf67842SDouglas Gilbert 			++k;
3710cbf67842SDouglas Gilbert 		}
37111da177e4SLinus Torvalds         }
37121da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
37131da177e4SLinus Torvalds 	stop_all_queued();
3714773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3715cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
3716cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
37171da177e4SLinus Torvalds 	return SUCCESS;
37181da177e4SLinus Torvalds }
37191da177e4SLinus Torvalds 
3720f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
37215f2578e5SFUJITA Tomonori 				      unsigned long store_size)
37221da177e4SLinus Torvalds {
37231da177e4SLinus Torvalds 	struct partition * pp;
37241da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
37251da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
37261da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
37271da177e4SLinus Torvalds 
37281da177e4SLinus Torvalds 	/* assume partition table already zeroed */
3729773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
37301da177e4SLinus Torvalds 		return;
3731773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
3732773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
3733c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
37341da177e4SLinus Torvalds 	}
3735c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
37361da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
3737773642d9SDouglas Gilbert 			   / sdebug_num_parts;
37381da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
37391da177e4SLinus Torvalds         starts[0] = sdebug_sectors_per;
3740773642d9SDouglas Gilbert 	for (k = 1; k < sdebug_num_parts; ++k)
37411da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
37421da177e4SLinus Torvalds 			    * heads_by_sects;
3743773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
3744773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
37451da177e4SLinus Torvalds 
37461da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
37471da177e4SLinus Torvalds 	ramp[511] = 0xAA;
37481da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
37491da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
37501da177e4SLinus Torvalds 		start_sec = starts[k];
37511da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
37521da177e4SLinus Torvalds 		pp->boot_ind = 0;
37531da177e4SLinus Torvalds 
37541da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
37551da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
37561da177e4SLinus Torvalds 			   / sdebug_sectors_per;
37571da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
37581da177e4SLinus Torvalds 
37591da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
37601da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
37611da177e4SLinus Torvalds 			       / sdebug_sectors_per;
37621da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
37631da177e4SLinus Torvalds 
3764150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
3765150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
37661da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
37671da177e4SLinus Torvalds 	}
37681da177e4SLinus Torvalds }
37691da177e4SLinus Torvalds 
3770fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
3771cbf67842SDouglas Gilbert 			 int scsi_result, int delta_jiff)
37721da177e4SLinus Torvalds {
3773cbf67842SDouglas Gilbert 	unsigned long iflags;
3774cd62b7daSDouglas Gilbert 	int k, num_in_q, qdepth, inject;
3775cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp = NULL;
3776299b6c07STomas Winkler 	struct scsi_device *sdp;
3777a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
37781da177e4SLinus Torvalds 
3779f46eb0e9SDouglas Gilbert 	if (unlikely(WARN_ON(!cmnd)))
3780299b6c07STomas Winkler 		return SCSI_MLQUEUE_HOST_BUSY;
3781299b6c07STomas Winkler 
3782f46eb0e9SDouglas Gilbert 	if (unlikely(NULL == devip)) {
3783f46eb0e9SDouglas Gilbert 		if (0 == scsi_result)
3784f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
3785f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
37861da177e4SLinus Torvalds 	}
3787299b6c07STomas Winkler 
3788299b6c07STomas Winkler 	sdp = cmnd->device;
3789299b6c07STomas Winkler 
3790f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose && scsi_result))
3791cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
3792cbf67842SDouglas Gilbert 			    __func__, scsi_result);
3793cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
3794cd62b7daSDouglas Gilbert 		goto respond_in_thread;
37951da177e4SLinus Torvalds 
3796cd62b7daSDouglas Gilbert 	/* schedule the response at a later time if resources permit */
37971da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
3798cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
3799cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
3800cbf67842SDouglas Gilbert 	inject = 0;
3801f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
3802cd62b7daSDouglas Gilbert 		if (scsi_result) {
3803cd62b7daSDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
3804cd62b7daSDouglas Gilbert 			goto respond_in_thread;
3805cd62b7daSDouglas Gilbert 		} else
3806cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
3807f46eb0e9SDouglas Gilbert 	} else if (unlikely((sdebug_every_nth != 0) &&
3808773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
3809f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
3810cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
3811cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
3812773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
3813cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
3814cbf67842SDouglas Gilbert 			inject = 1;
3815cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
38161da177e4SLinus Torvalds 		}
3817cbf67842SDouglas Gilbert 	}
3818cbf67842SDouglas Gilbert 
3819773642d9SDouglas Gilbert 	k = find_first_zero_bit(queued_in_use_bm, sdebug_max_queue);
3820f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
38211da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
3822cd62b7daSDouglas Gilbert 		if (scsi_result)
3823cd62b7daSDouglas Gilbert 			goto respond_in_thread;
3824773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
3825cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
3826773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
3827cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
3828cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
3829773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
3830cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
3831cbf67842SDouglas Gilbert 						    "report: host busy"));
3832cd62b7daSDouglas Gilbert 		if (scsi_result)
3833cd62b7daSDouglas Gilbert 			goto respond_in_thread;
3834cd62b7daSDouglas Gilbert 		else
3835cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
38361da177e4SLinus Torvalds 	}
3837cbf67842SDouglas Gilbert 	__set_bit(k, queued_in_use_bm);
3838cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
3839cbf67842SDouglas Gilbert 	sqcp = &queued_arr[k];
38401da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
3841cbf67842SDouglas Gilbert 	cmnd->result = scsi_result;
38421da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
3843a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
3844b333a819SDouglas Gilbert 	if ((delta_jiff > 0) || (sdebug_ndelay > 0)) {
3845b333a819SDouglas Gilbert 		ktime_t kt;
3846cbf67842SDouglas Gilbert 
3847b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
3848b333a819SDouglas Gilbert 			struct timespec ts;
3849b333a819SDouglas Gilbert 
3850b333a819SDouglas Gilbert 			jiffies_to_timespec(delta_jiff, &ts);
3851b333a819SDouglas Gilbert 			kt = ktime_set(ts.tv_sec, ts.tv_nsec);
3852b333a819SDouglas Gilbert 		} else
3853b333a819SDouglas Gilbert 			kt = ktime_set(0, sdebug_ndelay);
3854a10bc12aSDouglas Gilbert 		if (NULL == sd_dp) {
3855a10bc12aSDouglas Gilbert 			sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
3856a10bc12aSDouglas Gilbert 			if (NULL == sd_dp)
3857cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
3858a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
3859a10bc12aSDouglas Gilbert 			hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
3860cbf67842SDouglas Gilbert 				     HRTIMER_MODE_REL);
3861a10bc12aSDouglas Gilbert 			sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
3862a10bc12aSDouglas Gilbert 			sd_dp->qa_indx = k;
3863cbf67842SDouglas Gilbert 		}
3864a10bc12aSDouglas Gilbert 		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL);
3865c2206098SDouglas Gilbert 	} else {	/* jdelay < 0 */
3866a10bc12aSDouglas Gilbert 		if (NULL == sd_dp) {
3867a10bc12aSDouglas Gilbert 			sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC);
3868a10bc12aSDouglas Gilbert 			if (NULL == sd_dp)
3869cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
3870a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
3871a10bc12aSDouglas Gilbert 			sd_dp->qa_indx = k;
3872a10bc12aSDouglas Gilbert 			INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
3873cbf67842SDouglas Gilbert 		}
3874a10bc12aSDouglas Gilbert 		schedule_work(&sd_dp->ew.work);
3875cbf67842SDouglas Gilbert 	}
3876f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
3877f46eb0e9SDouglas Gilbert 		     (scsi_result == device_qfull_result)))
3878cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3879cbf67842SDouglas Gilbert 			    "%s: num_in_q=%d +1, %s%s\n", __func__,
3880cbf67842SDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""),
3881cbf67842SDouglas Gilbert 			    "status: TASK SET FULL");
38821da177e4SLinus Torvalds 	return 0;
3883cd62b7daSDouglas Gilbert 
3884cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
3885cd62b7daSDouglas Gilbert 	cmnd->result = scsi_result;
3886cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
3887cd62b7daSDouglas Gilbert 	return 0;
38881da177e4SLinus Torvalds }
3889cbf67842SDouglas Gilbert 
389023183910SDouglas Gilbert /* Note: The following macros create attribute files in the
389123183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
389223183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
389323183910SDouglas Gilbert    as it can when the corresponding attribute in the
389423183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
389523183910SDouglas Gilbert  */
3896773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
3897773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
3898773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
3899c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
3900773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
3901773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
3902773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
3903773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
3904773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
3905773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
3906773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
3907773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
3908773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
3909773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
3910773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
3911773642d9SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
3912773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
3913773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
3914773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
3915773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
3916773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
3917773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
3918773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
3919773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
3920773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
3921773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
3922773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
3923773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
3924773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
3925773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
3926773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
3927773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
3928773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
3929773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
3930773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
3931773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
3932773642d9SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
3933773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
393423183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
3935773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
39365b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
39371da177e4SLinus Torvalds 
39381da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
39391da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
39401da177e4SLinus Torvalds MODULE_LICENSE("GPL");
39411da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION);
39421da177e4SLinus Torvalds 
39431da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
39445b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
39450759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
3946cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
3947c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
39485b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
39495b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
3950c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
3951beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
395223183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
39535b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
3954185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
39555b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
39565b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
39575b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
3958be1dd78dSEric Sandeen MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
39595b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
3960c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
3961cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
3962cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
3963c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
396478d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
39651da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
3966c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
396732c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
39686f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
39695b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
39701da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
3971d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
3972e46b0344SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])");
3973ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
3974c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
39755b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
39765b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
39776014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
39786014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
3979c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
39805b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
39815b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
39821da177e4SLinus Torvalds 
39831da177e4SLinus Torvalds static char sdebug_info[256];
39841da177e4SLinus Torvalds 
39851da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp)
39861da177e4SLinus Torvalds {
39871da177e4SLinus Torvalds 	sprintf(sdebug_info, "scsi_debug, version %s [%s], "
39881da177e4SLinus Torvalds 		"dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
3989773642d9SDouglas Gilbert 		sdebug_version_date, sdebug_dev_size_mb, sdebug_opts);
39901da177e4SLinus Torvalds 	return sdebug_info;
39911da177e4SLinus Torvalds }
39921da177e4SLinus Torvalds 
3993cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
3994fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
3995fd32119bSDouglas Gilbert 				 int length)
39961da177e4SLinus Torvalds {
39971da177e4SLinus Torvalds 	char arr[16];
3998c8ed555aSAl Viro 	int opts;
39991da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
40001da177e4SLinus Torvalds 
40011da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
40021da177e4SLinus Torvalds 		return -EACCES;
40031da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
40041da177e4SLinus Torvalds 	arr[minLen] = '\0';
4005c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
40061da177e4SLinus Torvalds 		return -EINVAL;
4007773642d9SDouglas Gilbert 	sdebug_opts = opts;
4008773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4009773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4010773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
4011cbf67842SDouglas Gilbert 		atomic_set(&sdebug_cmnd_count, 0);
40121da177e4SLinus Torvalds 	return length;
40131da177e4SLinus Torvalds }
4014c8ed555aSAl Viro 
4015cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4016cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
4017cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
4018c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4019c8ed555aSAl Viro {
4020cbf67842SDouglas Gilbert 	int f, l;
4021cbf67842SDouglas Gilbert 	char b[32];
4022cbf67842SDouglas Gilbert 
4023773642d9SDouglas Gilbert 	if (sdebug_every_nth > 0)
4024cbf67842SDouglas Gilbert 		snprintf(b, sizeof(b), " (curr:%d)",
4025773642d9SDouglas Gilbert 			 ((SDEBUG_OPT_RARE_TSF & sdebug_opts) ?
4026cbf67842SDouglas Gilbert 				atomic_read(&sdebug_a_tsf) :
4027cbf67842SDouglas Gilbert 				atomic_read(&sdebug_cmnd_count)));
4028cbf67842SDouglas Gilbert 	else
4029cbf67842SDouglas Gilbert 		b[0] = '\0';
4030cbf67842SDouglas Gilbert 
4031cbf67842SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n"
40321da177e4SLinus Torvalds 		"num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
4033cbf67842SDouglas Gilbert 		"every_nth=%d%s\n"
4034cbf67842SDouglas Gilbert 		"delay=%d, ndelay=%d, max_luns=%d, q_completions=%d\n"
40351da177e4SLinus Torvalds 		"sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
4036cbf67842SDouglas Gilbert 		"command aborts=%d; RESETs: device=%d, target=%d, bus=%d, "
4037cbf67842SDouglas Gilbert 		"host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d "
4038cbf67842SDouglas Gilbert 		"usec_in_jiffy=%lu\n",
4039773642d9SDouglas Gilbert 		SCSI_DEBUG_VERSION, sdebug_version_date,
4040773642d9SDouglas Gilbert 		sdebug_num_tgts, sdebug_dev_size_mb, sdebug_opts,
4041c2206098SDouglas Gilbert 		sdebug_every_nth, b, sdebug_jdelay, sdebug_ndelay,
4042773642d9SDouglas Gilbert 		sdebug_max_luns, atomic_read(&sdebug_completions),
4043773642d9SDouglas Gilbert 		sdebug_sector_size, sdebug_cylinders_per, sdebug_heads,
4044cbf67842SDouglas Gilbert 		sdebug_sectors_per, num_aborts, num_dev_resets,
4045cbf67842SDouglas Gilbert 		num_target_resets, num_bus_resets, num_host_resets,
4046cbf67842SDouglas Gilbert 		dix_reads, dix_writes, dif_errors, TICK_NSEC / 1000);
4047cbf67842SDouglas Gilbert 
4048773642d9SDouglas Gilbert 	f = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4049773642d9SDouglas Gilbert 	if (f != sdebug_max_queue) {
4050773642d9SDouglas Gilbert 		l = find_last_bit(queued_in_use_bm, sdebug_max_queue);
4051cbf67842SDouglas Gilbert 		seq_printf(m, "   %s BUSY: first,last bits set: %d,%d\n",
4052cbf67842SDouglas Gilbert 			   "queued_in_use_bm", f, l);
4053cbf67842SDouglas Gilbert 	}
4054c8ed555aSAl Viro 	return 0;
40551da177e4SLinus Torvalds }
40561da177e4SLinus Torvalds 
405782069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
40581da177e4SLinus Torvalds {
4059c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
40601da177e4SLinus Torvalds }
4061c2206098SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued */
406282069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
406382069379SAkinobu Mita 			   size_t count)
40641da177e4SLinus Torvalds {
4065c2206098SDouglas Gilbert 	int jdelay, res;
40661da177e4SLinus Torvalds 
4067c2206098SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &jdelay))) {
4068cbf67842SDouglas Gilbert 		res = count;
4069c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
4070cbf67842SDouglas Gilbert 			unsigned long iflags;
4071cbf67842SDouglas Gilbert 			int k;
4072cbf67842SDouglas Gilbert 
4073cbf67842SDouglas Gilbert 			spin_lock_irqsave(&queued_arr_lock, iflags);
4074773642d9SDouglas Gilbert 			k = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4075773642d9SDouglas Gilbert 			if (k != sdebug_max_queue)
4076cbf67842SDouglas Gilbert 				res = -EBUSY;	/* have queued commands */
4077cbf67842SDouglas Gilbert 			else {
4078a10bc12aSDouglas Gilbert 				/* make sure sdebug_defer instances get
4079a10bc12aSDouglas Gilbert 				 * re-allocated for new delay variant */
4080a10bc12aSDouglas Gilbert 				free_all_queued();
4081c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
4082773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
40831da177e4SLinus Torvalds 			}
4084cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
4085cbf67842SDouglas Gilbert 		}
4086cbf67842SDouglas Gilbert 		return res;
40871da177e4SLinus Torvalds 	}
40881da177e4SLinus Torvalds 	return -EINVAL;
40891da177e4SLinus Torvalds }
409082069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
40911da177e4SLinus Torvalds 
4092cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4093cbf67842SDouglas Gilbert {
4094773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
4095cbf67842SDouglas Gilbert }
4096cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
4097c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
4098cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
4099cbf67842SDouglas Gilbert 			    size_t count)
4100cbf67842SDouglas Gilbert {
4101cbf67842SDouglas Gilbert 	unsigned long iflags;
4102cbf67842SDouglas Gilbert 	int ndelay, res, k;
4103cbf67842SDouglas Gilbert 
4104cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4105cbf67842SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < 1000000000)) {
4106cbf67842SDouglas Gilbert 		res = count;
4107773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
4108cbf67842SDouglas Gilbert 			spin_lock_irqsave(&queued_arr_lock, iflags);
4109773642d9SDouglas Gilbert 			k = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4110773642d9SDouglas Gilbert 			if (k != sdebug_max_queue)
4111cbf67842SDouglas Gilbert 				res = -EBUSY;	/* have queued commands */
4112cbf67842SDouglas Gilbert 			else {
4113a10bc12aSDouglas Gilbert 				/* make sure sdebug_defer instances get
4114a10bc12aSDouglas Gilbert 				 * re-allocated for new delay variant */
4115a10bc12aSDouglas Gilbert 				free_all_queued();
4116773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
4117c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
4118c2206098SDouglas Gilbert 							: DEF_JDELAY;
4119cbf67842SDouglas Gilbert 			}
4120cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
4121cbf67842SDouglas Gilbert 		}
4122cbf67842SDouglas Gilbert 		return res;
4123cbf67842SDouglas Gilbert 	}
4124cbf67842SDouglas Gilbert 	return -EINVAL;
4125cbf67842SDouglas Gilbert }
4126cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
4127cbf67842SDouglas Gilbert 
412882069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
41291da177e4SLinus Torvalds {
4130773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
41311da177e4SLinus Torvalds }
41321da177e4SLinus Torvalds 
413382069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
413482069379SAkinobu Mita 			  size_t count)
41351da177e4SLinus Torvalds {
41361da177e4SLinus Torvalds         int opts;
41371da177e4SLinus Torvalds 	char work[20];
41381da177e4SLinus Torvalds 
41391da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
414048a96876SRasmus Villemoes 		if (0 == strncasecmp(work,"0x", 2)) {
41411da177e4SLinus Torvalds 			if (1 == sscanf(&work[2], "%x", &opts))
41421da177e4SLinus Torvalds 				goto opts_done;
41431da177e4SLinus Torvalds 		} else {
41441da177e4SLinus Torvalds 			if (1 == sscanf(work, "%d", &opts))
41451da177e4SLinus Torvalds 				goto opts_done;
41461da177e4SLinus Torvalds 		}
41471da177e4SLinus Torvalds 	}
41481da177e4SLinus Torvalds 	return -EINVAL;
41491da177e4SLinus Torvalds opts_done:
4150773642d9SDouglas Gilbert 	sdebug_opts = opts;
4151773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4152773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4153cbf67842SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
4154cbf67842SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
41551da177e4SLinus Torvalds 	return count;
41561da177e4SLinus Torvalds }
415782069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
41581da177e4SLinus Torvalds 
415982069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
41601da177e4SLinus Torvalds {
4161773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
41621da177e4SLinus Torvalds }
416382069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
416482069379SAkinobu Mita 			   size_t count)
41651da177e4SLinus Torvalds {
41661da177e4SLinus Torvalds         int n;
41671da177e4SLinus Torvalds 
41681da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4169773642d9SDouglas Gilbert 		sdebug_ptype = n;
41701da177e4SLinus Torvalds 		return count;
41711da177e4SLinus Torvalds 	}
41721da177e4SLinus Torvalds 	return -EINVAL;
41731da177e4SLinus Torvalds }
417482069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
41751da177e4SLinus Torvalds 
417682069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
41771da177e4SLinus Torvalds {
4178773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
41791da177e4SLinus Torvalds }
418082069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
418182069379SAkinobu Mita 			    size_t count)
41821da177e4SLinus Torvalds {
41831da177e4SLinus Torvalds         int n;
41841da177e4SLinus Torvalds 
41851da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4186773642d9SDouglas Gilbert 		sdebug_dsense = n;
41871da177e4SLinus Torvalds 		return count;
41881da177e4SLinus Torvalds 	}
41891da177e4SLinus Torvalds 	return -EINVAL;
41901da177e4SLinus Torvalds }
419182069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
41921da177e4SLinus Torvalds 
419382069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
419423183910SDouglas Gilbert {
4195773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
419623183910SDouglas Gilbert }
419782069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
419882069379SAkinobu Mita 			     size_t count)
419923183910SDouglas Gilbert {
420023183910SDouglas Gilbert         int n;
420123183910SDouglas Gilbert 
420223183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4203cbf67842SDouglas Gilbert 		n = (n > 0);
4204773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
4205773642d9SDouglas Gilbert 		if (sdebug_fake_rw != n) {
4206cbf67842SDouglas Gilbert 			if ((0 == n) && (NULL == fake_storep)) {
4207cbf67842SDouglas Gilbert 				unsigned long sz =
4208773642d9SDouglas Gilbert 					(unsigned long)sdebug_dev_size_mb *
4209cbf67842SDouglas Gilbert 					1048576;
4210cbf67842SDouglas Gilbert 
4211cbf67842SDouglas Gilbert 				fake_storep = vmalloc(sz);
4212cbf67842SDouglas Gilbert 				if (NULL == fake_storep) {
4213c1287970STomas Winkler 					pr_err("out of memory, 9\n");
4214cbf67842SDouglas Gilbert 					return -ENOMEM;
4215cbf67842SDouglas Gilbert 				}
4216cbf67842SDouglas Gilbert 				memset(fake_storep, 0, sz);
4217cbf67842SDouglas Gilbert 			}
4218773642d9SDouglas Gilbert 			sdebug_fake_rw = n;
4219cbf67842SDouglas Gilbert 		}
422023183910SDouglas Gilbert 		return count;
422123183910SDouglas Gilbert 	}
422223183910SDouglas Gilbert 	return -EINVAL;
422323183910SDouglas Gilbert }
422482069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
422523183910SDouglas Gilbert 
422682069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
4227c65b1445SDouglas Gilbert {
4228773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
4229c65b1445SDouglas Gilbert }
423082069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
423182069379SAkinobu Mita 			      size_t count)
4232c65b1445SDouglas Gilbert {
4233c65b1445SDouglas Gilbert         int n;
4234c65b1445SDouglas Gilbert 
4235c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4236773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
4237c65b1445SDouglas Gilbert 		return count;
4238c65b1445SDouglas Gilbert 	}
4239c65b1445SDouglas Gilbert 	return -EINVAL;
4240c65b1445SDouglas Gilbert }
424182069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
4242c65b1445SDouglas Gilbert 
424382069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
42441da177e4SLinus Torvalds {
4245773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
42461da177e4SLinus Torvalds }
424782069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
424882069379SAkinobu Mita 			      size_t count)
42491da177e4SLinus Torvalds {
42501da177e4SLinus Torvalds         int n;
42511da177e4SLinus Torvalds 
42521da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4253773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
42541da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
42551da177e4SLinus Torvalds 		return count;
42561da177e4SLinus Torvalds 	}
42571da177e4SLinus Torvalds 	return -EINVAL;
42581da177e4SLinus Torvalds }
425982069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
42601da177e4SLinus Torvalds 
426182069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
42621da177e4SLinus Torvalds {
4263773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
42641da177e4SLinus Torvalds }
426582069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
42661da177e4SLinus Torvalds 
426782069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
42681da177e4SLinus Torvalds {
4269773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
42701da177e4SLinus Torvalds }
427182069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
42721da177e4SLinus Torvalds 
427382069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
42741da177e4SLinus Torvalds {
4275773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
42761da177e4SLinus Torvalds }
427782069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
427882069379SAkinobu Mita 			       size_t count)
42791da177e4SLinus Torvalds {
42801da177e4SLinus Torvalds         int nth;
42811da177e4SLinus Torvalds 
42821da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
4283773642d9SDouglas Gilbert 		sdebug_every_nth = nth;
4284cbf67842SDouglas Gilbert 		atomic_set(&sdebug_cmnd_count, 0);
42851da177e4SLinus Torvalds 		return count;
42861da177e4SLinus Torvalds 	}
42871da177e4SLinus Torvalds 	return -EINVAL;
42881da177e4SLinus Torvalds }
428982069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
42901da177e4SLinus Torvalds 
429182069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
42921da177e4SLinus Torvalds {
4293773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
42941da177e4SLinus Torvalds }
429582069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
429682069379SAkinobu Mita 			      size_t count)
42971da177e4SLinus Torvalds {
42981da177e4SLinus Torvalds         int n;
429919c8ead7SEwan D. Milne 	bool changed;
43001da177e4SLinus Torvalds 
43011da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4302773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
4303773642d9SDouglas Gilbert 		sdebug_max_luns = n;
43041da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
4305773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
430619c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
430719c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
430819c8ead7SEwan D. Milne 
430919c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
431019c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
431119c8ead7SEwan D. Milne 					    host_list) {
431219c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
431319c8ead7SEwan D. Milne 						    dev_list) {
431419c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
431519c8ead7SEwan D. Milne 						dp->uas_bm);
431619c8ead7SEwan D. Milne 				}
431719c8ead7SEwan D. Milne 			}
431819c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
431919c8ead7SEwan D. Milne 		}
43201da177e4SLinus Torvalds 		return count;
43211da177e4SLinus Torvalds 	}
43221da177e4SLinus Torvalds 	return -EINVAL;
43231da177e4SLinus Torvalds }
432482069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
43251da177e4SLinus Torvalds 
432682069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
432778d4e5a0SDouglas Gilbert {
4328773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
432978d4e5a0SDouglas Gilbert }
4330cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
4331cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
433282069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
433382069379SAkinobu Mita 			       size_t count)
433478d4e5a0SDouglas Gilbert {
4335cbf67842SDouglas Gilbert 	unsigned long iflags;
4336cbf67842SDouglas Gilbert 	int n, k;
433778d4e5a0SDouglas Gilbert 
433878d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
433978d4e5a0SDouglas Gilbert 	    (n <= SCSI_DEBUG_CANQUEUE)) {
4340cbf67842SDouglas Gilbert 		spin_lock_irqsave(&queued_arr_lock, iflags);
4341cbf67842SDouglas Gilbert 		k = find_last_bit(queued_in_use_bm, SCSI_DEBUG_CANQUEUE);
4342773642d9SDouglas Gilbert 		sdebug_max_queue = n;
4343cbf67842SDouglas Gilbert 		if (SCSI_DEBUG_CANQUEUE == k)
4344cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4345cbf67842SDouglas Gilbert 		else if (k >= n)
4346cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4347cbf67842SDouglas Gilbert 		else
4348cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4349cbf67842SDouglas Gilbert 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
435078d4e5a0SDouglas Gilbert 		return count;
435178d4e5a0SDouglas Gilbert 	}
435278d4e5a0SDouglas Gilbert 	return -EINVAL;
435378d4e5a0SDouglas Gilbert }
435482069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
435578d4e5a0SDouglas Gilbert 
435682069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
435778d4e5a0SDouglas Gilbert {
4358773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
435978d4e5a0SDouglas Gilbert }
436082069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
436178d4e5a0SDouglas Gilbert 
436282069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
43631da177e4SLinus Torvalds {
4364773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
43651da177e4SLinus Torvalds }
436682069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
43671da177e4SLinus Torvalds 
436882069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
4369c65b1445SDouglas Gilbert {
4370773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
4371c65b1445SDouglas Gilbert }
437282069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
437382069379SAkinobu Mita 				size_t count)
4374c65b1445SDouglas Gilbert {
4375c65b1445SDouglas Gilbert         int n;
43760d01c5dfSDouglas Gilbert 	bool changed;
4377c65b1445SDouglas Gilbert 
4378c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4379773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
4380773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
438128898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
43820d01c5dfSDouglas Gilbert 		if (changed) {
43830d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
43840d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
438528898873SFUJITA Tomonori 
43864bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
43870d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
43880d01c5dfSDouglas Gilbert 					    host_list) {
43890d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
43900d01c5dfSDouglas Gilbert 						    dev_list) {
43910d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
43920d01c5dfSDouglas Gilbert 						dp->uas_bm);
43930d01c5dfSDouglas Gilbert 				}
43940d01c5dfSDouglas Gilbert 			}
43954bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
43960d01c5dfSDouglas Gilbert 		}
4397c65b1445SDouglas Gilbert 		return count;
4398c65b1445SDouglas Gilbert 	}
4399c65b1445SDouglas Gilbert 	return -EINVAL;
4400c65b1445SDouglas Gilbert }
440182069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
4402c65b1445SDouglas Gilbert 
440382069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
44041da177e4SLinus Torvalds {
4405773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
44061da177e4SLinus Torvalds }
44071da177e4SLinus Torvalds 
4408fd32119bSDouglas Gilbert static int sdebug_add_adapter(void);
4409fd32119bSDouglas Gilbert static void sdebug_remove_adapter(void);
4410fd32119bSDouglas Gilbert 
441182069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
441282069379SAkinobu Mita 			      size_t count)
44131da177e4SLinus Torvalds {
44141da177e4SLinus Torvalds 	int delta_hosts;
44151da177e4SLinus Torvalds 
4416f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
44171da177e4SLinus Torvalds 		return -EINVAL;
44181da177e4SLinus Torvalds 	if (delta_hosts > 0) {
44191da177e4SLinus Torvalds 		do {
44201da177e4SLinus Torvalds 			sdebug_add_adapter();
44211da177e4SLinus Torvalds 		} while (--delta_hosts);
44221da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
44231da177e4SLinus Torvalds 		do {
44241da177e4SLinus Torvalds 			sdebug_remove_adapter();
44251da177e4SLinus Torvalds 		} while (++delta_hosts);
44261da177e4SLinus Torvalds 	}
44271da177e4SLinus Torvalds 	return count;
44281da177e4SLinus Torvalds }
442982069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
44301da177e4SLinus Torvalds 
443182069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
443223183910SDouglas Gilbert {
4433773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
443423183910SDouglas Gilbert }
443582069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
443682069379SAkinobu Mita 				    size_t count)
443723183910SDouglas Gilbert {
443823183910SDouglas Gilbert 	int n;
443923183910SDouglas Gilbert 
444023183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4441773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
444223183910SDouglas Gilbert 		return count;
444323183910SDouglas Gilbert 	}
444423183910SDouglas Gilbert 	return -EINVAL;
444523183910SDouglas Gilbert }
444682069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
444723183910SDouglas Gilbert 
444882069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
4449597136abSMartin K. Petersen {
4450773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
4451597136abSMartin K. Petersen }
445282069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
4453597136abSMartin K. Petersen 
445482069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
4455c6a44287SMartin K. Petersen {
4456773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
4457c6a44287SMartin K. Petersen }
445882069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
4459c6a44287SMartin K. Petersen 
446082069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
4461c6a44287SMartin K. Petersen {
4462773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
4463c6a44287SMartin K. Petersen }
446482069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
4465c6a44287SMartin K. Petersen 
446682069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
4467c6a44287SMartin K. Petersen {
4468773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
4469c6a44287SMartin K. Petersen }
447082069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
4471c6a44287SMartin K. Petersen 
447282069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
4473c6a44287SMartin K. Petersen {
4474773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
4475c6a44287SMartin K. Petersen }
447682069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
4477c6a44287SMartin K. Petersen 
447882069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
447944d92694SMartin K. Petersen {
448044d92694SMartin K. Petersen 	ssize_t count;
448144d92694SMartin K. Petersen 
44825b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
448344d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
448444d92694SMartin K. Petersen 				 sdebug_store_sectors);
448544d92694SMartin K. Petersen 
4486c7badc90STejun Heo 	count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
4487c7badc90STejun Heo 			  (int)map_size, map_storep);
448844d92694SMartin K. Petersen 	buf[count++] = '\n';
4489c7badc90STejun Heo 	buf[count] = '\0';
449044d92694SMartin K. Petersen 
449144d92694SMartin K. Petersen 	return count;
449244d92694SMartin K. Petersen }
449382069379SAkinobu Mita static DRIVER_ATTR_RO(map);
449444d92694SMartin K. Petersen 
449582069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
4496d986788bSMartin Pitt {
4497773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
4498d986788bSMartin Pitt }
449982069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
450082069379SAkinobu Mita 			       size_t count)
4501d986788bSMartin Pitt {
4502d986788bSMartin Pitt 	int n;
4503d986788bSMartin Pitt 
4504d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4505773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
4506d986788bSMartin Pitt 		return count;
4507d986788bSMartin Pitt 	}
4508d986788bSMartin Pitt 	return -EINVAL;
4509d986788bSMartin Pitt }
451082069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
4511d986788bSMartin Pitt 
4512cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4513cbf67842SDouglas Gilbert {
4514773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
4515cbf67842SDouglas Gilbert }
4516185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
4517cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4518cbf67842SDouglas Gilbert 			       size_t count)
4519cbf67842SDouglas Gilbert {
4520185dd232SDouglas Gilbert 	int n;
4521cbf67842SDouglas Gilbert 
4522cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4523185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
4524185dd232SDouglas Gilbert 		return count;
4525cbf67842SDouglas Gilbert 	}
4526cbf67842SDouglas Gilbert 	return -EINVAL;
4527cbf67842SDouglas Gilbert }
4528cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
4529cbf67842SDouglas Gilbert 
4530c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
4531c2248fc9SDouglas Gilbert {
4532773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
4533c2248fc9SDouglas Gilbert }
4534c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4535c2248fc9SDouglas Gilbert 			    size_t count)
4536c2248fc9SDouglas Gilbert {
4537c2248fc9SDouglas Gilbert 	int n;
4538c2248fc9SDouglas Gilbert 
4539c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4540773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
4541c2248fc9SDouglas Gilbert 		return count;
4542c2248fc9SDouglas Gilbert 	}
4543c2248fc9SDouglas Gilbert 	return -EINVAL;
4544c2248fc9SDouglas Gilbert }
4545c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
4546c2248fc9SDouglas Gilbert 
4547cbf67842SDouglas Gilbert 
454882069379SAkinobu Mita /* Note: The following array creates attribute files in the
454923183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
455023183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
455123183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
455223183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
455323183910SDouglas Gilbert  */
45546ecaff7fSRandy Dunlap 
455582069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
455682069379SAkinobu Mita 	&driver_attr_delay.attr,
455782069379SAkinobu Mita 	&driver_attr_opts.attr,
455882069379SAkinobu Mita 	&driver_attr_ptype.attr,
455982069379SAkinobu Mita 	&driver_attr_dsense.attr,
456082069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
456182069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
456282069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
456382069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
456482069379SAkinobu Mita 	&driver_attr_num_parts.attr,
456582069379SAkinobu Mita 	&driver_attr_every_nth.attr,
456682069379SAkinobu Mita 	&driver_attr_max_luns.attr,
456782069379SAkinobu Mita 	&driver_attr_max_queue.attr,
456882069379SAkinobu Mita 	&driver_attr_no_uld.attr,
456982069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
457082069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
457182069379SAkinobu Mita 	&driver_attr_add_host.attr,
457282069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
457382069379SAkinobu Mita 	&driver_attr_sector_size.attr,
457482069379SAkinobu Mita 	&driver_attr_dix.attr,
457582069379SAkinobu Mita 	&driver_attr_dif.attr,
457682069379SAkinobu Mita 	&driver_attr_guard.attr,
457782069379SAkinobu Mita 	&driver_attr_ato.attr,
457882069379SAkinobu Mita 	&driver_attr_map.attr,
457982069379SAkinobu Mita 	&driver_attr_removable.attr,
4580cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
4581cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
4582c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
458382069379SAkinobu Mita 	NULL,
458482069379SAkinobu Mita };
458582069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
45861da177e4SLinus Torvalds 
458711ddcecaSAkinobu Mita static struct device *pseudo_primary;
45888dea0d02SFUJITA Tomonori 
45891da177e4SLinus Torvalds static int __init scsi_debug_init(void)
45901da177e4SLinus Torvalds {
45915f2578e5SFUJITA Tomonori 	unsigned long sz;
45921da177e4SLinus Torvalds 	int host_to_add;
45931da177e4SLinus Torvalds 	int k;
45946ecaff7fSRandy Dunlap 	int ret;
45951da177e4SLinus Torvalds 
4596cbf67842SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
4597cbf67842SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
4598cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
4599cbf67842SDouglas Gilbert 
4600773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
4601c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
4602773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
4603773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
4604c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
4605cbf67842SDouglas Gilbert 
4606773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
4607597136abSMartin K. Petersen 	case  512:
4608597136abSMartin K. Petersen 	case 1024:
4609597136abSMartin K. Petersen 	case 2048:
4610597136abSMartin K. Petersen 	case 4096:
4611597136abSMartin K. Petersen 		break;
4612597136abSMartin K. Petersen 	default:
4613773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
4614597136abSMartin K. Petersen 		return -EINVAL;
4615597136abSMartin K. Petersen 	}
4616597136abSMartin K. Petersen 
4617773642d9SDouglas Gilbert 	switch (sdebug_dif) {
4618c6a44287SMartin K. Petersen 
4619c6a44287SMartin K. Petersen 	case SD_DIF_TYPE0_PROTECTION:
4620f46eb0e9SDouglas Gilbert 		break;
4621c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
4622395cef03SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
4623c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
4624f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
4625c6a44287SMartin K. Petersen 		break;
4626c6a44287SMartin K. Petersen 
4627c6a44287SMartin K. Petersen 	default:
4628c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
4629c6a44287SMartin K. Petersen 		return -EINVAL;
4630c6a44287SMartin K. Petersen 	}
4631c6a44287SMartin K. Petersen 
4632773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
4633c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
4634c6a44287SMartin K. Petersen 		return -EINVAL;
4635c6a44287SMartin K. Petersen 	}
4636c6a44287SMartin K. Petersen 
4637773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
4638c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
4639c6a44287SMartin K. Petersen 		return -EINVAL;
4640c6a44287SMartin K. Petersen 	}
4641c6a44287SMartin K. Petersen 
4642773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
4643773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
4644ea61fca5SMartin K. Petersen 		return -EINVAL;
4645ea61fca5SMartin K. Petersen 	}
4646ea61fca5SMartin K. Petersen 
4647773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
4648773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
4649ea61fca5SMartin K. Petersen 		return -EINVAL;
4650ea61fca5SMartin K. Petersen 	}
4651ea61fca5SMartin K. Petersen 
4652773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
4653773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
4654773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
4655773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
465628898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
46571da177e4SLinus Torvalds 
46581da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
46591da177e4SLinus Torvalds 	sdebug_heads = 8;
46601da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
4661773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
46621da177e4SLinus Torvalds 		sdebug_heads = 64;
4663773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
4664fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
46651da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
46661da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
46671da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
46681da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
46691da177e4SLinus Torvalds 		sdebug_heads = 255;
46701da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
46711da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
46721da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
46731da177e4SLinus Torvalds 	}
46741da177e4SLinus Torvalds 
4675773642d9SDouglas Gilbert 	if (0 == sdebug_fake_rw) {
46761da177e4SLinus Torvalds 		fake_storep = vmalloc(sz);
46771da177e4SLinus Torvalds 		if (NULL == fake_storep) {
4678c1287970STomas Winkler 			pr_err("out of memory, 1\n");
46791da177e4SLinus Torvalds 			return -ENOMEM;
46801da177e4SLinus Torvalds 		}
46811da177e4SLinus Torvalds 		memset(fake_storep, 0, sz);
4682773642d9SDouglas Gilbert 		if (sdebug_num_parts > 0)
4683f58b0efbSFUJITA Tomonori 			sdebug_build_parts(fake_storep, sz);
4684cbf67842SDouglas Gilbert 	}
46851da177e4SLinus Torvalds 
4686773642d9SDouglas Gilbert 	if (sdebug_dix) {
4687c6a44287SMartin K. Petersen 		int dif_size;
4688c6a44287SMartin K. Petersen 
4689c6a44287SMartin K. Petersen 		dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
4690c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
4691c6a44287SMartin K. Petersen 
4692c1287970STomas Winkler 		pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
4693c6a44287SMartin K. Petersen 
4694c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
4695c1287970STomas Winkler 			pr_err("out of mem. (DIX)\n");
4696c6a44287SMartin K. Petersen 			ret = -ENOMEM;
4697c6a44287SMartin K. Petersen 			goto free_vm;
4698c6a44287SMartin K. Petersen 		}
4699c6a44287SMartin K. Petersen 
4700c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
4701c6a44287SMartin K. Petersen 	}
4702c6a44287SMartin K. Petersen 
47035b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
47045b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
4705773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
4706773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
47076014759cSMartin K. Petersen 
4708773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
4709773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
47106014759cSMartin K. Petersen 
4711773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
4712773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
47136014759cSMartin K. Petersen 
4714773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
4715773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
4716773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
4717c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
471844d92694SMartin K. Petersen 			return -EINVAL;
471944d92694SMartin K. Petersen 		}
472044d92694SMartin K. Petersen 
4721b90ebc3dSAkinobu Mita 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
4722b90ebc3dSAkinobu Mita 		map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
472344d92694SMartin K. Petersen 
4724c1287970STomas Winkler 		pr_info("%lu provisioning blocks\n", map_size);
472544d92694SMartin K. Petersen 
472644d92694SMartin K. Petersen 		if (map_storep == NULL) {
4727c1287970STomas Winkler 			pr_err("out of mem. (MAP)\n");
472844d92694SMartin K. Petersen 			ret = -ENOMEM;
472944d92694SMartin K. Petersen 			goto free_vm;
473044d92694SMartin K. Petersen 		}
473144d92694SMartin K. Petersen 
4732b90ebc3dSAkinobu Mita 		bitmap_zero(map_storep, map_size);
473344d92694SMartin K. Petersen 
473444d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
4735773642d9SDouglas Gilbert 		if (sdebug_num_parts)
473644d92694SMartin K. Petersen 			map_region(0, 2);
473744d92694SMartin K. Petersen 	}
473844d92694SMartin K. Petersen 
47399b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
47409b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
4741c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
47429b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
47436ecaff7fSRandy Dunlap 		goto free_vm;
47446ecaff7fSRandy Dunlap 	}
47456ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
47466ecaff7fSRandy Dunlap 	if (ret < 0) {
4747c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
47486ecaff7fSRandy Dunlap 		goto dev_unreg;
47496ecaff7fSRandy Dunlap 	}
47506ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
47516ecaff7fSRandy Dunlap 	if (ret < 0) {
4752c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
47536ecaff7fSRandy Dunlap 		goto bus_unreg;
47546ecaff7fSRandy Dunlap 	}
47551da177e4SLinus Torvalds 
4756773642d9SDouglas Gilbert 	host_to_add = sdebug_add_host;
4757773642d9SDouglas Gilbert 	sdebug_add_host = 0;
47581da177e4SLinus Torvalds 
47591da177e4SLinus Torvalds         for (k = 0; k < host_to_add; k++) {
47601da177e4SLinus Torvalds                 if (sdebug_add_adapter()) {
4761c1287970STomas Winkler 			pr_err("sdebug_add_adapter failed k=%d\n", k);
47621da177e4SLinus Torvalds                         break;
47631da177e4SLinus Torvalds                 }
47641da177e4SLinus Torvalds         }
47651da177e4SLinus Torvalds 
4766773642d9SDouglas Gilbert 	if (sdebug_verbose)
4767773642d9SDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_add_host);
4768c1287970STomas Winkler 
47691da177e4SLinus Torvalds 	return 0;
47706ecaff7fSRandy Dunlap 
47716ecaff7fSRandy Dunlap bus_unreg:
47726ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
47736ecaff7fSRandy Dunlap dev_unreg:
47749b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
47756ecaff7fSRandy Dunlap free_vm:
477644d92694SMartin K. Petersen 	vfree(map_storep);
4777c6a44287SMartin K. Petersen 	vfree(dif_storep);
47786ecaff7fSRandy Dunlap 	vfree(fake_storep);
47796ecaff7fSRandy Dunlap 
47806ecaff7fSRandy Dunlap 	return ret;
47811da177e4SLinus Torvalds }
47821da177e4SLinus Torvalds 
47831da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
47841da177e4SLinus Torvalds {
4785773642d9SDouglas Gilbert 	int k = sdebug_add_host;
47861da177e4SLinus Torvalds 
47871da177e4SLinus Torvalds 	stop_all_queued();
4788cbf67842SDouglas Gilbert 	free_all_queued();
47891da177e4SLinus Torvalds 	for (; k; k--)
47901da177e4SLinus Torvalds 		sdebug_remove_adapter();
47911da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
47921da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
47939b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
47941da177e4SLinus Torvalds 
4795c6a44287SMartin K. Petersen 	vfree(dif_storep);
47961da177e4SLinus Torvalds 	vfree(fake_storep);
47971da177e4SLinus Torvalds }
47981da177e4SLinus Torvalds 
47991da177e4SLinus Torvalds device_initcall(scsi_debug_init);
48001da177e4SLinus Torvalds module_exit(scsi_debug_exit);
48011da177e4SLinus Torvalds 
48021da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev)
48031da177e4SLinus Torvalds {
48041da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
48051da177e4SLinus Torvalds 
48061da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
48071da177e4SLinus Torvalds         kfree(sdbg_host);
48081da177e4SLinus Torvalds }
48091da177e4SLinus Torvalds 
48101da177e4SLinus Torvalds static int sdebug_add_adapter(void)
48111da177e4SLinus Torvalds {
48121da177e4SLinus Torvalds 	int k, devs_per_host;
48131da177e4SLinus Torvalds         int error = 0;
48141da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
48158b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
48161da177e4SLinus Torvalds 
481724669f75SJes Sorensen         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
48181da177e4SLinus Torvalds         if (NULL == sdbg_host) {
4819c1287970STomas Winkler 		pr_err("out of memory at line %d\n", __LINE__);
48201da177e4SLinus Torvalds                 return -ENOMEM;
48211da177e4SLinus Torvalds         }
48221da177e4SLinus Torvalds 
48231da177e4SLinus Torvalds         INIT_LIST_HEAD(&sdbg_host->dev_info_list);
48241da177e4SLinus Torvalds 
4825773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
48261da177e4SLinus Torvalds         for (k = 0; k < devs_per_host; k++) {
48275cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
48285cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
4829c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
48301da177e4SLinus Torvalds                         error = -ENOMEM;
48311da177e4SLinus Torvalds 			goto clean;
48321da177e4SLinus Torvalds                 }
48331da177e4SLinus Torvalds         }
48341da177e4SLinus Torvalds 
48351da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
48361da177e4SLinus Torvalds         list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
48371da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
48381da177e4SLinus Torvalds 
48391da177e4SLinus Torvalds         sdbg_host->dev.bus = &pseudo_lld_bus;
48409b906779SNicholas Bellinger         sdbg_host->dev.parent = pseudo_primary;
48411da177e4SLinus Torvalds         sdbg_host->dev.release = &sdebug_release_adapter;
4842773642d9SDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
48431da177e4SLinus Torvalds 
48441da177e4SLinus Torvalds         error = device_register(&sdbg_host->dev);
48451da177e4SLinus Torvalds 
48461da177e4SLinus Torvalds         if (error)
48471da177e4SLinus Torvalds 		goto clean;
48481da177e4SLinus Torvalds 
4849773642d9SDouglas Gilbert 	++sdebug_add_host;
48501da177e4SLinus Torvalds         return error;
48511da177e4SLinus Torvalds 
48521da177e4SLinus Torvalds clean:
48538b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
48548b40228fSFUJITA Tomonori 				 dev_list) {
48551da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
48561da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
48571da177e4SLinus Torvalds 	}
48581da177e4SLinus Torvalds 
48591da177e4SLinus Torvalds 	kfree(sdbg_host);
48601da177e4SLinus Torvalds         return error;
48611da177e4SLinus Torvalds }
48621da177e4SLinus Torvalds 
48631da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
48641da177e4SLinus Torvalds {
48651da177e4SLinus Torvalds         struct sdebug_host_info * sdbg_host = NULL;
48661da177e4SLinus Torvalds 
48671da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
48681da177e4SLinus Torvalds         if (!list_empty(&sdebug_host_list)) {
48691da177e4SLinus Torvalds                 sdbg_host = list_entry(sdebug_host_list.prev,
48701da177e4SLinus Torvalds                                        struct sdebug_host_info, host_list);
48711da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
48721da177e4SLinus Torvalds 	}
48731da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
48741da177e4SLinus Torvalds 
48751da177e4SLinus Torvalds 	if (!sdbg_host)
48761da177e4SLinus Torvalds 		return;
48771da177e4SLinus Torvalds 
48781da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
4879773642d9SDouglas Gilbert 	--sdebug_add_host;
48801da177e4SLinus Torvalds }
48811da177e4SLinus Torvalds 
4882fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
4883cbf67842SDouglas Gilbert {
4884cbf67842SDouglas Gilbert 	int num_in_q = 0;
4885cbf67842SDouglas Gilbert 	unsigned long iflags;
4886cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4887cbf67842SDouglas Gilbert 
4888cbf67842SDouglas Gilbert 	spin_lock_irqsave(&queued_arr_lock, iflags);
4889cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
4890cbf67842SDouglas Gilbert 	if (NULL == devip) {
4891cbf67842SDouglas Gilbert 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
4892cbf67842SDouglas Gilbert 		return	-ENODEV;
4893cbf67842SDouglas Gilbert 	}
4894cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
4895cbf67842SDouglas Gilbert 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
4896c40ecc12SChristoph Hellwig 
4897cbf67842SDouglas Gilbert 	if (qdepth < 1)
4898cbf67842SDouglas Gilbert 		qdepth = 1;
4899cbf67842SDouglas Gilbert 	/* allow to exceed max host queued_arr elements for testing */
4900cbf67842SDouglas Gilbert 	if (qdepth > SCSI_DEBUG_CANQUEUE + 10)
4901cbf67842SDouglas Gilbert 		qdepth = SCSI_DEBUG_CANQUEUE + 10;
4902db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
4903cbf67842SDouglas Gilbert 
4904773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
4905cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev,
4906c40ecc12SChristoph Hellwig 			    "%s: qdepth=%d, num_in_q=%d\n",
4907c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
4908cbf67842SDouglas Gilbert 	}
4909cbf67842SDouglas Gilbert 	return sdev->queue_depth;
4910cbf67842SDouglas Gilbert }
4911cbf67842SDouglas Gilbert 
4912fd32119bSDouglas Gilbert static int check_inject(struct scsi_cmnd *scp)
4913817fd66bSDouglas Gilbert {
4914817fd66bSDouglas Gilbert 	struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
4915817fd66bSDouglas Gilbert 
4916817fd66bSDouglas Gilbert 	memset(ep, 0, sizeof(struct sdebug_scmd_extra_t));
4917817fd66bSDouglas Gilbert 
4918773642d9SDouglas Gilbert 	if (atomic_inc_return(&sdebug_cmnd_count) >= abs(sdebug_every_nth)) {
4919817fd66bSDouglas Gilbert 		atomic_set(&sdebug_cmnd_count, 0);
4920773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
4921773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
4922773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
4923817fd66bSDouglas Gilbert 			return 1; /* ignore command causing timeout */
4924773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
4925817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
4926817fd66bSDouglas Gilbert 			return 1; /* time out reads and writes */
4927817fd66bSDouglas Gilbert 		if (sdebug_any_injecting_opt) {
4928773642d9SDouglas Gilbert 			if (SDEBUG_OPT_RECOVERED_ERR & sdebug_opts)
4929817fd66bSDouglas Gilbert 				ep->inj_recovered = true;
4930773642d9SDouglas Gilbert 			if (SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts)
4931817fd66bSDouglas Gilbert 				ep->inj_transport = true;
4932773642d9SDouglas Gilbert 			if (SDEBUG_OPT_DIF_ERR & sdebug_opts)
4933817fd66bSDouglas Gilbert 				ep->inj_dif = true;
4934773642d9SDouglas Gilbert 			if (SDEBUG_OPT_DIX_ERR & sdebug_opts)
4935817fd66bSDouglas Gilbert 				ep->inj_dix = true;
4936773642d9SDouglas Gilbert 			if (SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts)
4937817fd66bSDouglas Gilbert 				ep->inj_short = true;
4938817fd66bSDouglas Gilbert 		}
4939817fd66bSDouglas Gilbert 	}
4940817fd66bSDouglas Gilbert 	return 0;
4941817fd66bSDouglas Gilbert }
4942817fd66bSDouglas Gilbert 
4943fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
4944fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
4945c2248fc9SDouglas Gilbert {
4946c2248fc9SDouglas Gilbert 	u8 sdeb_i;
4947c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
4948c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
4949c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
4950c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
4951c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
4952c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
4953c2248fc9SDouglas Gilbert 	int k, na;
4954c2248fc9SDouglas Gilbert 	int errsts = 0;
4955c2248fc9SDouglas Gilbert 	u32 flags;
4956c2248fc9SDouglas Gilbert 	u16 sa;
4957c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
4958c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
4959c2248fc9SDouglas Gilbert 
4960c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
4961f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
4962f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
4963c2248fc9SDouglas Gilbert 		char b[120];
4964c2248fc9SDouglas Gilbert 		int n, len, sb;
4965c2248fc9SDouglas Gilbert 
4966c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
4967c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
4968c2248fc9SDouglas Gilbert 		if (len > 32)
4969c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
4970c2248fc9SDouglas Gilbert 		else {
4971c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
4972c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
4973c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
4974c2248fc9SDouglas Gilbert 		}
4975c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, b);
4976c2248fc9SDouglas Gilbert 	}
497734d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
4978f46eb0e9SDouglas Gilbert 	if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
4979f46eb0e9SDouglas Gilbert 		goto err_out;
4980c2248fc9SDouglas Gilbert 
4981c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
4982c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
4983c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
4984f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
4985f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
4986c2248fc9SDouglas Gilbert 		if (NULL == devip)
4987f46eb0e9SDouglas Gilbert 			goto err_out;
4988c2248fc9SDouglas Gilbert 	}
4989c2248fc9SDouglas Gilbert 	na = oip->num_attached;
4990c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
4991c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
4992c2248fc9SDouglas Gilbert 		r_oip = oip;
4993c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
4994c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
4995c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
4996c2248fc9SDouglas Gilbert 			else
4997c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
4998c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
4999c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
5000c2248fc9SDouglas Gilbert 					break;
5001c2248fc9SDouglas Gilbert 			}
5002c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
5003c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5004c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
5005c2248fc9SDouglas Gilbert 					break;
5006c2248fc9SDouglas Gilbert 			}
5007c2248fc9SDouglas Gilbert 		}
5008c2248fc9SDouglas Gilbert 		if (k > na) {
5009c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
5010c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5011c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
5012c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5013c2248fc9SDouglas Gilbert 			else
5014c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
5015c2248fc9SDouglas Gilbert 			goto check_cond;
5016c2248fc9SDouglas Gilbert 		}
5017c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
5018c2248fc9SDouglas Gilbert 	flags = oip->flags;
5019f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
5020c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5021c2248fc9SDouglas Gilbert 		goto check_cond;
5022c2248fc9SDouglas Gilbert 	}
5023f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
5024773642d9SDouglas Gilbert 		if (sdebug_verbose)
5025773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5026773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
5027c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5028c2248fc9SDouglas Gilbert 		goto check_cond;
5029c2248fc9SDouglas Gilbert 	}
5030f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
5031c2248fc9SDouglas Gilbert 		u8 rem;
5032c2248fc9SDouglas Gilbert 		int j;
5033c2248fc9SDouglas Gilbert 
5034c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5035c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
5036c2248fc9SDouglas Gilbert 			if (rem) {
5037c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
5038c2248fc9SDouglas Gilbert 					if (0x80 & rem)
5039c2248fc9SDouglas Gilbert 						break;
5040c2248fc9SDouglas Gilbert 				}
5041c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5042c2248fc9SDouglas Gilbert 				goto check_cond;
5043c2248fc9SDouglas Gilbert 			}
5044c2248fc9SDouglas Gilbert 		}
5045c2248fc9SDouglas Gilbert 	}
5046f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
5047f46eb0e9SDouglas Gilbert 		     SDEBUG_NUM_UAS != find_first_bit(devip->uas_bm,
5048f46eb0e9SDouglas Gilbert 						      SDEBUG_NUM_UAS))) {
5049f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
5050c2248fc9SDouglas Gilbert 		if (errsts)
5051c2248fc9SDouglas Gilbert 			goto check_cond;
5052c2248fc9SDouglas Gilbert 	}
5053f46eb0e9SDouglas Gilbert 	if (unlikely((F_M_ACCESS & flags) && devip->stopped)) {
5054c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
5055773642d9SDouglas Gilbert 		if (sdebug_verbose)
5056c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5057c2248fc9SDouglas Gilbert 				    "%s\n", my_name, "initializing command "
5058c2248fc9SDouglas Gilbert 				    "required");
5059c2248fc9SDouglas Gilbert 		errsts = check_condition_result;
5060c2248fc9SDouglas Gilbert 		goto fini;
5061c2248fc9SDouglas Gilbert 	}
5062773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
5063c2248fc9SDouglas Gilbert 		goto fini;
5064f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
5065c2248fc9SDouglas Gilbert 		if (check_inject(scp))
5066c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
5067c2248fc9SDouglas Gilbert 	}
5068f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
5069f46eb0e9SDouglas Gilbert 		errsts = oip->pfp(scp, devip);	/* calls a resp_* function */
5070c2248fc9SDouglas Gilbert 	else if (r_pfp)	/* if leaf function ptr NULL, try the root's */
5071c2248fc9SDouglas Gilbert 		errsts = r_pfp(scp, devip);
5072c2248fc9SDouglas Gilbert 
5073c2248fc9SDouglas Gilbert fini:
5074c2248fc9SDouglas Gilbert 	return schedule_resp(scp, devip, errsts,
5075c2206098SDouglas Gilbert 			     ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay));
5076c2248fc9SDouglas Gilbert check_cond:
5077c2248fc9SDouglas Gilbert 	return schedule_resp(scp, devip, check_condition_result, 0);
5078f46eb0e9SDouglas Gilbert err_out:
5079f46eb0e9SDouglas Gilbert 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0);
5080c2248fc9SDouglas Gilbert }
5081c2248fc9SDouglas Gilbert 
50829e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
5083c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
5084c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
50859e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
50869e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
50879e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
50889e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
50899e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
50909e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
50919e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
5092185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
5093cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
50949e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
50959e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
5096cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
5097cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
50989e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
50999e603ca0SFUJITA Tomonori 	.can_queue =		SCSI_DEBUG_CANQUEUE,
51009e603ca0SFUJITA Tomonori 	.this_id =		7,
510165e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
5102cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
51036bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
51049e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
51059e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
5106c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
5107817fd66bSDouglas Gilbert 	.cmd_size =		sizeof(struct sdebug_scmd_extra_t),
51089e603ca0SFUJITA Tomonori };
51099e603ca0SFUJITA Tomonori 
51101da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev)
51111da177e4SLinus Torvalds {
51121da177e4SLinus Torvalds 	int error = 0;
51131da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
51141da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
5115f46eb0e9SDouglas Gilbert 	int hprot;
51161da177e4SLinus Torvalds 
51171da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
51181da177e4SLinus Torvalds 
5119773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
5120773642d9SDouglas Gilbert 	if (sdebug_clustering)
51210759c666SAkinobu Mita 		sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
51221da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
51231da177e4SLinus Torvalds 	if (NULL == hpnt) {
5124c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
51251da177e4SLinus Torvalds 		error = -ENODEV;
51261da177e4SLinus Torvalds 		return error;
51271da177e4SLinus Torvalds 	}
51281da177e4SLinus Torvalds 
51291da177e4SLinus Torvalds         sdbg_host->shost = hpnt;
51301da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
5131773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5132773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
51331da177e4SLinus Torvalds 	else
5134773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
5135773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
5136f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
51371da177e4SLinus Torvalds 
5138f46eb0e9SDouglas Gilbert 	hprot = 0;
5139c6a44287SMartin K. Petersen 
5140773642d9SDouglas Gilbert 	switch (sdebug_dif) {
5141c6a44287SMartin K. Petersen 
5142c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
5143f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
5144773642d9SDouglas Gilbert 		if (sdebug_dix)
5145f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
5146c6a44287SMartin K. Petersen 		break;
5147c6a44287SMartin K. Petersen 
5148c6a44287SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
5149f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
5150773642d9SDouglas Gilbert 		if (sdebug_dix)
5151f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
5152c6a44287SMartin K. Petersen 		break;
5153c6a44287SMartin K. Petersen 
5154c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
5155f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
5156773642d9SDouglas Gilbert 		if (sdebug_dix)
5157f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
5158c6a44287SMartin K. Petersen 		break;
5159c6a44287SMartin K. Petersen 
5160c6a44287SMartin K. Petersen 	default:
5161773642d9SDouglas Gilbert 		if (sdebug_dix)
5162f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
5163c6a44287SMartin K. Petersen 		break;
5164c6a44287SMartin K. Petersen 	}
5165c6a44287SMartin K. Petersen 
5166f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
5167c6a44287SMartin K. Petersen 
5168f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
5169c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
5170f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5171f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5172f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5173f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5174f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5175f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5176f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
5177c6a44287SMartin K. Petersen 
5178773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
5179c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5180c6a44287SMartin K. Petersen 	else
5181c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5182c6a44287SMartin K. Petersen 
5183773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5184773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
51851da177e4SLinus Torvalds         error = scsi_add_host(hpnt, &sdbg_host->dev);
51861da177e4SLinus Torvalds         if (error) {
5187c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
51881da177e4SLinus Torvalds                 error = -ENODEV;
51891da177e4SLinus Torvalds 		scsi_host_put(hpnt);
51901da177e4SLinus Torvalds         } else
51911da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
51921da177e4SLinus Torvalds 
51931da177e4SLinus Torvalds 	return error;
51941da177e4SLinus Torvalds }
51951da177e4SLinus Torvalds 
51961da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev)
51971da177e4SLinus Torvalds {
51981da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
51998b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
52001da177e4SLinus Torvalds 
52011da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
52021da177e4SLinus Torvalds 
52031da177e4SLinus Torvalds 	if (!sdbg_host) {
5204c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
52051da177e4SLinus Torvalds 		return -ENODEV;
52061da177e4SLinus Torvalds 	}
52071da177e4SLinus Torvalds 
52081da177e4SLinus Torvalds         scsi_remove_host(sdbg_host->shost);
52091da177e4SLinus Torvalds 
52108b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
52118b40228fSFUJITA Tomonori 				 dev_list) {
52121da177e4SLinus Torvalds                 list_del(&sdbg_devinfo->dev_list);
52131da177e4SLinus Torvalds                 kfree(sdbg_devinfo);
52141da177e4SLinus Torvalds         }
52151da177e4SLinus Torvalds 
52161da177e4SLinus Torvalds         scsi_host_put(sdbg_host->shost);
52171da177e4SLinus Torvalds         return 0;
52181da177e4SLinus Torvalds }
52191da177e4SLinus Torvalds 
52208dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
52218dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
52221da177e4SLinus Torvalds {
52238dea0d02SFUJITA Tomonori 	return 1;
52248dea0d02SFUJITA Tomonori }
52251da177e4SLinus Torvalds 
52268dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
52278dea0d02SFUJITA Tomonori 	.name = "pseudo",
52288dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
52298dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
52308dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
523182069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
52328dea0d02SFUJITA Tomonori };
5233