xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 80c49563)
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  *
980c49563SDouglas Gilbert  * Copyright (C) 2001 - 2018 Douglas Gilbert
101da177e4SLinus Torvalds  *
11773642d9SDouglas Gilbert  * This program is free software; you can redistribute it and/or modify
12773642d9SDouglas Gilbert  * it under the terms of the GNU General Public License as published by
13773642d9SDouglas Gilbert  * the Free Software Foundation; either version 2, or (at your option)
14773642d9SDouglas Gilbert  * any later version.
151da177e4SLinus Torvalds  *
1678d4e5a0SDouglas Gilbert  *  For documentation see http://sg.danny.cz/sg/sdebug26.html
171da177e4SLinus Torvalds  *
181da177e4SLinus Torvalds  */
191da177e4SLinus Torvalds 
20c1287970STomas Winkler 
21c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
22c1287970STomas Winkler 
231da177e4SLinus Torvalds #include <linux/module.h>
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds #include <linux/kernel.h>
261da177e4SLinus Torvalds #include <linux/errno.h>
27b333a819SDouglas Gilbert #include <linux/jiffies.h>
285a0e3ad6STejun Heo #include <linux/slab.h>
291da177e4SLinus Torvalds #include <linux/types.h>
301da177e4SLinus Torvalds #include <linux/string.h>
311da177e4SLinus Torvalds #include <linux/genhd.h>
321da177e4SLinus Torvalds #include <linux/fs.h>
331da177e4SLinus Torvalds #include <linux/init.h>
341da177e4SLinus Torvalds #include <linux/proc_fs.h>
351da177e4SLinus Torvalds #include <linux/vmalloc.h>
361da177e4SLinus Torvalds #include <linux/moduleparam.h>
37852e034dSJens Axboe #include <linux/scatterlist.h>
381da177e4SLinus Torvalds #include <linux/blkdev.h>
39c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h>
40cbf67842SDouglas Gilbert #include <linux/spinlock.h>
41cbf67842SDouglas Gilbert #include <linux/interrupt.h>
42cbf67842SDouglas Gilbert #include <linux/atomic.h>
43cbf67842SDouglas Gilbert #include <linux/hrtimer.h>
4409ba24c1SDouglas Gilbert #include <linux/uuid.h>
456ebf105cSChristoph Hellwig #include <linux/t10-pi.h>
46c6a44287SMartin K. Petersen 
47c6a44287SMartin K. Petersen #include <net/checksum.h>
489ff26eefSFUJITA Tomonori 
4944d92694SMartin K. Petersen #include <asm/unaligned.h>
5044d92694SMartin K. Petersen 
519ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
529ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
539ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
541da177e4SLinus Torvalds #include <scsi/scsi_host.h>
551da177e4SLinus Torvalds #include <scsi/scsicam.h>
56a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
57cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h>
58395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
591da177e4SLinus Torvalds 
60c6a44287SMartin K. Petersen #include "sd.h"
611da177e4SLinus Torvalds #include "scsi_logging.h"
621da177e4SLinus Torvalds 
63773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */
6480c49563SDouglas Gilbert #define SDEBUG_VERSION "0188"	/* format to fit INQUIRY revision field */
6580c49563SDouglas Gilbert static const char *sdebug_version_date = "20180128";
66cbf67842SDouglas Gilbert 
67cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
681da177e4SLinus Torvalds 
696f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
70c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
71c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
72c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
731da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
74c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
751da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7622017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
771da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
78c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
79cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
80cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
8119c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
8219c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8322017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8422017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
85cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
86cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
87cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
8822017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9
891da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
906f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
91c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
92c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
9322017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d
94acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1	/* with TARGET_CHANGED_ASC */
95acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
96481b5e5cSDouglas Gilbert #define WRITE_ERROR_ASC 0xc
971da177e4SLinus Torvalds 
986f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
996f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
1006f3cbf55SDouglas Gilbert 
1011da177e4SLinus Torvalds /* Default values for driver parameters */
1021da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1031da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1041da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1051da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1061da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1071da177e4SLinus Torvalds  */
1085b94e232SMartin K. Petersen #define DEF_ATO 1
1099b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10
110c2206098SDouglas Gilbert #define DEF_JDELAY   1		/* if > 0 unit is a jiffy */
1111da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1125b94e232SMartin K. Petersen #define DEF_DIF 0
1135b94e232SMartin K. Petersen #define DEF_DIX 0
1145b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1151da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1165b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1175b94e232SMartin K. Petersen #define DEF_GUARD 0
118cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1195b94e232SMartin K. Petersen #define DEF_LBPU 0
1205b94e232SMartin K. Petersen #define DEF_LBPWS 0
1215b94e232SMartin K. Petersen #define DEF_LBPWS10 0
122be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1235b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
124cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1255b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1261da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1271da177e4SLinus Torvalds #define DEF_OPTS   0
12832c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1295b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
13086e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0
131b01f6f83SDouglas Gilbert #define DEF_PTYPE   TYPE_DISK
132d986788bSMartin Pitt #define DEF_REMOVABLE false
133760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
1345b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1355b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1365b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1376014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1386014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1395b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1405b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1415b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
142c2248fc9SDouglas Gilbert #define DEF_STRICT 0
143c4837394SDouglas Gilbert #define DEF_STATISTICS false
144c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1
14509ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0
146c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999
1471da177e4SLinus Torvalds 
148b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0
149b01f6f83SDouglas Gilbert 
150773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
151773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
152773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
153773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
154773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
155773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
156773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
157773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
158773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
159773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
160773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
161773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF		0x400
162773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF		0x800
163773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE		0x1000
164773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE		0x2000
165773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE		0x4000
1667ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY		0x8000
167773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
168773642d9SDouglas Gilbert 			      SDEBUG_OPT_RESET_NOISE)
169773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
170773642d9SDouglas Gilbert 				  SDEBUG_OPT_TRANSPORT_ERR | \
171773642d9SDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
1727ee6d1b4SBart Van Assche 				  SDEBUG_OPT_SHORT_TRANSFER | \
1737ee6d1b4SBart Van Assche 				  SDEBUG_OPT_HOST_BUSY)
1741da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
175fd32119bSDouglas Gilbert  *   - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
1761da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
177773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_RECOVERED_ERR is set.
1786f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
179773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_TRANSPORT_ERR is set.
1801da177e4SLinus Torvalds  *
1811da177e4SLinus Torvalds  * When "every_nth" < 0 then after "- every_nth" commands:
182fd32119bSDouglas Gilbert  *   - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
1831da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
184773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_RECOVERED_ERR is set.
1856f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
186773642d9SDouglas Gilbert  *     commands if _DEBUG_OPT_TRANSPORT_ERR is set.
187773642d9SDouglas Gilbert  * This will continue on every subsequent command until some other action
188773642d9SDouglas Gilbert  * occurs (e.g. the user * writing a new value (other than -1 or 1) to
189773642d9SDouglas Gilbert  * every_nth via sysfs).
1901da177e4SLinus Torvalds  */
1911da177e4SLinus Torvalds 
192cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
193cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
194cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
195cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
196cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
197cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1
198cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2
1990d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3
20019c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4
201acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5	/* simulate firmware change */
202acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
203acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7
204cbf67842SDouglas Gilbert 
205773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
2061da177e4SLinus Torvalds  * sector on read commands: */
2071da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
20832f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
2111da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
2121da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
2131da177e4SLinus Torvalds 
214c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
215c4837394SDouglas Gilbert  * (for response) per submit queue at one time. Can be reduced by max_queue
216c4837394SDouglas Gilbert  * option. Command responses are not queued when jdelay=0 and ndelay=0. The
217c4837394SDouglas Gilbert  * per-device DEF_CMD_PER_LUN can be changed via sysfs:
218c4837394SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
219c4837394SDouglas Gilbert  * but cannot exceed SDEBUG_CANQUEUE .
220c4837394SDouglas Gilbert  */
221c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS  3	/* a WORD is bits in a long */
222c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE  (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
223cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN  255
224cbf67842SDouglas Gilbert 
225fd32119bSDouglas Gilbert #define F_D_IN			1
226fd32119bSDouglas Gilbert #define F_D_OUT			2
227fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
228fd32119bSDouglas Gilbert #define F_D_UNKN		8
229fd32119bSDouglas Gilbert #define F_RL_WLUN_OK		0x10
230fd32119bSDouglas Gilbert #define F_SKIP_UA		0x20
231fd32119bSDouglas Gilbert #define F_DELAY_OVERR		0x40
232fd32119bSDouglas Gilbert #define F_SA_LOW		0x80	/* cdb byte 1, bits 4 to 0 */
233fd32119bSDouglas Gilbert #define F_SA_HIGH		0x100	/* as used by variable length cdbs */
234fd32119bSDouglas Gilbert #define F_INV_OP		0x200
235fd32119bSDouglas Gilbert #define F_FAKE_RW		0x400
236fd32119bSDouglas Gilbert #define F_M_ACCESS		0x800	/* media access */
23780c49563SDouglas Gilbert #define F_LONG_DELAY		0x1000
238fd32119bSDouglas Gilbert 
239fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
24046f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
241fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
242fd32119bSDouglas Gilbert 
243fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4
244fd32119bSDouglas Gilbert 
245b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32
246fd32119bSDouglas Gilbert 
247fd32119bSDouglas Gilbert 
248fd32119bSDouglas Gilbert struct sdebug_dev_info {
249fd32119bSDouglas Gilbert 	struct list_head dev_list;
250fd32119bSDouglas Gilbert 	unsigned int channel;
251fd32119bSDouglas Gilbert 	unsigned int target;
252fd32119bSDouglas Gilbert 	u64 lun;
253bf476433SChristoph Hellwig 	uuid_t lu_name;
254fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
255fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
256fd32119bSDouglas Gilbert 	atomic_t num_in_q;
257c4837394SDouglas Gilbert 	atomic_t stopped;
258fd32119bSDouglas Gilbert 	bool used;
259fd32119bSDouglas Gilbert };
260fd32119bSDouglas Gilbert 
261fd32119bSDouglas Gilbert struct sdebug_host_info {
262fd32119bSDouglas Gilbert 	struct list_head host_list;
263fd32119bSDouglas Gilbert 	struct Scsi_Host *shost;
264fd32119bSDouglas Gilbert 	struct device dev;
265fd32119bSDouglas Gilbert 	struct list_head dev_info_list;
266fd32119bSDouglas Gilbert };
267fd32119bSDouglas Gilbert 
268fd32119bSDouglas Gilbert #define to_sdebug_host(d)	\
269fd32119bSDouglas Gilbert 	container_of(d, struct sdebug_host_info, dev)
270fd32119bSDouglas Gilbert 
27110bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
27210bde980SDouglas Gilbert 		      SDEB_DEFER_WQ = 2};
27310bde980SDouglas Gilbert 
274fd32119bSDouglas Gilbert struct sdebug_defer {
275fd32119bSDouglas Gilbert 	struct hrtimer hrt;
276fd32119bSDouglas Gilbert 	struct execute_work ew;
277c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
278c4837394SDouglas Gilbert 	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
279c4837394SDouglas Gilbert 	int issuing_cpu;
28010bde980SDouglas Gilbert 	bool init_hrt;
28110bde980SDouglas Gilbert 	bool init_wq;
28210bde980SDouglas Gilbert 	enum sdeb_defer_type defer_t;
283fd32119bSDouglas Gilbert };
284fd32119bSDouglas Gilbert 
285fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
286c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
287c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
288c4837394SDouglas Gilbert 	 */
289fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
290fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
291c4837394SDouglas Gilbert 	unsigned int inj_recovered:1;
292c4837394SDouglas Gilbert 	unsigned int inj_transport:1;
293c4837394SDouglas Gilbert 	unsigned int inj_dif:1;
294c4837394SDouglas Gilbert 	unsigned int inj_dix:1;
295c4837394SDouglas Gilbert 	unsigned int inj_short:1;
2967ee6d1b4SBart Van Assche 	unsigned int inj_host_busy:1;
297fd32119bSDouglas Gilbert };
298fd32119bSDouglas Gilbert 
299c4837394SDouglas Gilbert struct sdebug_queue {
300c4837394SDouglas Gilbert 	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
301c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
302c4837394SDouglas Gilbert 	spinlock_t qc_lock;
303c4837394SDouglas Gilbert 	atomic_t blocked;	/* to temporarily stop more being queued */
304fd32119bSDouglas Gilbert };
305fd32119bSDouglas Gilbert 
306c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
307c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
308c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
309c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
310c4837394SDouglas Gilbert 
311fd32119bSDouglas Gilbert struct opcode_info_t {
312b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
313b01f6f83SDouglas Gilbert 				/* for terminating element */
314fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
315fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
316fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
317fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
318fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
3199a051019SDouglas Gilbert 	u8 len_mask[16];	/* len_mask[0]-->cdb_len, then mask for cdb */
3209a051019SDouglas Gilbert 				/* 1 to min(cdb_len, 15); ignore cdb[15...] */
321fd32119bSDouglas Gilbert };
322fd32119bSDouglas Gilbert 
323fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
324c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
325c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
326c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
327c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
328c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
329c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
330c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
331c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
332c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
333c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
334c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
335c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
336c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
33746f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_IN_16 = 12,	/* add ...SERV_ACT_IN_12 if needed */
33846f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT_16 = 13,	/* add ...SERV_ACT_OUT_12 if needed */
339c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
340c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
341c2248fc9SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* 10 only */
342481b5e5cSDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,	/* READ(32), WRITE(32), WR_SCAT(32) */
343c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
344c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
345c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
346c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
347c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
348c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
349c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
350c2248fc9SDouglas Gilbert 	SDEB_I_XDWRITEREAD = 25,	/* 10 only */
351c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_BUFFER = 26,
352c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_SAME = 27,		/* 10, 16 */
35380c49563SDouglas Gilbert 	SDEB_I_SYNC_CACHE = 28,		/* 10, 16 */
354c2248fc9SDouglas Gilbert 	SDEB_I_COMP_WRITE = 29,
3559a051019SDouglas Gilbert 	SDEB_I_LAST_ELEMENT = 30,	/* keep this last (previous + 1) */
356c2248fc9SDouglas Gilbert };
357c2248fc9SDouglas Gilbert 
358c4837394SDouglas Gilbert 
359c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
360c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
361c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
362c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
363c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
364c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
365c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
366c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
367c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
368c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
369c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
370c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
371c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
372c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
373c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
374c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
375c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
376c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
377c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
378c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
379fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
380c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
381c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
382c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
383c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
384c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
385c2248fc9SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
38680c49563SDouglas Gilbert 	0, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
38746f64e70SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
388c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
389c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
390c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
39146f64e70SDouglas Gilbert 	SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
39246f64e70SDouglas Gilbert 	     0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
393c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
394c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
395c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
396c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
397c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
398c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
399c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
400c2248fc9SDouglas Gilbert };
401c2248fc9SDouglas Gilbert 
40280c49563SDouglas Gilbert /*
40380c49563SDouglas Gilbert  * The following "response" functions return the SCSI mid-level's 4 byte
40480c49563SDouglas Gilbert  * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
40580c49563SDouglas Gilbert  * command completion, they can mask their return value with
40680c49563SDouglas Gilbert  * SDEG_RES_IMMED_MASK .
40780c49563SDouglas Gilbert  */
40880c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000
40980c49563SDouglas Gilbert 
410c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
411c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
412c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
413c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
414c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
415c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
416c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
417c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
418c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
419481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
420c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
421c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
422c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
423c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
424c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
42538d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
42638d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
427c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
428c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
429c2248fc9SDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
43038d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
431acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
43280c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
433c2248fc9SDouglas Gilbert 
43446f64e70SDouglas Gilbert /*
43546f64e70SDouglas Gilbert  * The following are overflow arrays for cdbs that "hit" the same index in
43646f64e70SDouglas Gilbert  * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
43746f64e70SDouglas Gilbert  * should be placed in opcode_info_arr[], the others should be placed here.
43846f64e70SDouglas Gilbert  */
43946f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = {
440c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
441c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
442c2248fc9SDouglas Gilbert };
443c2248fc9SDouglas Gilbert 
44446f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = {
445c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
446c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
447c2248fc9SDouglas Gilbert };
448c2248fc9SDouglas Gilbert 
44946f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = {
45046f64e70SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
451b7e24581SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
452c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
45346f64e70SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
454c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
45546f64e70SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
456b7e24581SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
457c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
458c2248fc9SDouglas Gilbert };
459c2248fc9SDouglas Gilbert 
46046f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = {
46146f64e70SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
46246f64e70SDouglas Gilbert 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
46346f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
46446f64e70SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
46546f64e70SDouglas Gilbert 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
46646f64e70SDouglas Gilbert 		   0, 0, 0} },
46746f64e70SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
46846f64e70SDouglas Gilbert 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
46946f64e70SDouglas Gilbert 		   0xbf, 0xc7, 0, 0, 0, 0} },
470c2248fc9SDouglas Gilbert };
471c2248fc9SDouglas Gilbert 
47246f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = {
473c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
474c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
47546f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
476c2248fc9SDouglas Gilbert };
477c2248fc9SDouglas Gilbert 
47846f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
47946f64e70SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
480b7e24581SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
481c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
482481b5e5cSDouglas Gilbert 	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
483481b5e5cSDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
484481b5e5cSDouglas Gilbert 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */
485c2248fc9SDouglas Gilbert };
486c2248fc9SDouglas Gilbert 
48746f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
48838d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
489c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
49046f64e70SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
49138d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
492c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
49346f64e70SDouglas Gilbert 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
494c2248fc9SDouglas Gilbert };
495c2248fc9SDouglas Gilbert 
49646f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = {
49746f64e70SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
498c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
49946f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
500c2248fc9SDouglas Gilbert };
501c2248fc9SDouglas Gilbert 
50246f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = {
503c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
504c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
505c2248fc9SDouglas Gilbert };
506c2248fc9SDouglas Gilbert 
50746f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = {
508c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
509c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
510c2248fc9SDouglas Gilbert };
511c2248fc9SDouglas Gilbert 
51280c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = {
51380c49563SDouglas Gilbert 	{0, 0x91, 0, F_LONG_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
51480c49563SDouglas Gilbert 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
51580c49563SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
51680c49563SDouglas Gilbert };
51780c49563SDouglas Gilbert 
518c2248fc9SDouglas Gilbert 
519c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
520c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
521c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
522c2248fc9SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
523c2248fc9SDouglas Gilbert /* 0 */
52446f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
525c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
52646f64e70SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
527c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
528c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
529c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
53046f64e70SDouglas Gilbert 	     0, 0} },					/* REPORT LUNS */
531c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
532c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
533c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
534c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
53546f64e70SDouglas Gilbert /* 5 */
53646f64e70SDouglas Gilbert 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
53746f64e70SDouglas Gilbert 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
53846f64e70SDouglas Gilbert 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
53946f64e70SDouglas Gilbert 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
54046f64e70SDouglas Gilbert 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
54146f64e70SDouglas Gilbert 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
54246f64e70SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
543c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
544c2248fc9SDouglas Gilbert 	     0, 0, 0} },
54546f64e70SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
546c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
547c2248fc9SDouglas Gilbert 	     0, 0} },
54846f64e70SDouglas Gilbert 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
54946f64e70SDouglas Gilbert 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
55046f64e70SDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
551c2248fc9SDouglas Gilbert /* 10 */
55246f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
55346f64e70SDouglas Gilbert 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
55446f64e70SDouglas Gilbert 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55580c49563SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
55680c49563SDouglas Gilbert 	{0, 0x1b, 0, F_LONG_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
557c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
55846f64e70SDouglas Gilbert 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
55946f64e70SDouglas Gilbert 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
56046f64e70SDouglas Gilbert 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
56146f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
562481b5e5cSDouglas Gilbert 	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
563481b5e5cSDouglas Gilbert 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
564481b5e5cSDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */
56546f64e70SDouglas Gilbert 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
56646f64e70SDouglas Gilbert 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
56746f64e70SDouglas Gilbert 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
56846f64e70SDouglas Gilbert 				0xff, 0, 0xc7, 0, 0, 0, 0} },
56946f64e70SDouglas Gilbert /* 15 */
570c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
571c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
57246f64e70SDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, NULL, NULL, /* VERIFY(10) */
573f7f9f26bSDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
574f7f9f26bSDouglas Gilbert 	     0, 0, 0, 0, 0, 0} },
57546f64e70SDouglas Gilbert 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
57646f64e70SDouglas Gilbert 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
57746f64e70SDouglas Gilbert 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
57846f64e70SDouglas Gilbert 	     0xff, 0xff} },
57946f64e70SDouglas Gilbert 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
58046f64e70SDouglas Gilbert 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
581c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
582c2248fc9SDouglas Gilbert 	     0} },
58346f64e70SDouglas Gilbert 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
58446f64e70SDouglas Gilbert 	    NULL, release_iarr, /* RELEASE(10) <no response function> */
585c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
586c2248fc9SDouglas Gilbert 	     0} },
587c2248fc9SDouglas Gilbert /* 20 */
588f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
589f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
590c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
591c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
592c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
593c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
594c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
595c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
59646f64e70SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
597b7e24581SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
59846f64e70SDouglas Gilbert /* 25 */
59946f64e70SDouglas Gilbert 	{0, 0x53, 0, F_D_IN | F_D_OUT | FF_MEDIA_IO, resp_xdwriteread_10,
600b7e24581SDouglas Gilbert 	    NULL, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
60146f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },		/* XDWRITEREAD(10) */
602acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
603acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
604acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
60546f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
60646f64e70SDouglas Gilbert 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
60746f64e70SDouglas Gilbert 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
60846f64e70SDouglas Gilbert 		 0, 0, 0, 0, 0} },
60980c49563SDouglas Gilbert 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_LONG_DELAY | F_M_ACCESS,
61080c49563SDouglas Gilbert 	    resp_sync_cache, sync_cache_iarr,
611b7e24581SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
61280c49563SDouglas Gilbert 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
61346f64e70SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
614c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
615b7e24581SDouglas Gilbert 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
616c2248fc9SDouglas Gilbert 
617c2248fc9SDouglas Gilbert /* 30 */
618c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
619c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
620c2248fc9SDouglas Gilbert };
621c2248fc9SDouglas Gilbert 
622773642d9SDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;
623773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
6249b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
625c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
626773642d9SDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
627773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
628773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
629773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
630773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
631773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
632773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
633773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
634773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
635c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
636d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
637d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
638cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
639c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
640773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
641773642d9SDouglas Gilbert static int sdebug_no_uld;
642773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
643773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
644773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
645773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
646773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
64786e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
648b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
649773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
650773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
651773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
652773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
653773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
654773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
655773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
656773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
657773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
658773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
659773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
660773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
661773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
66209ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
663773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
664773642d9SDouglas Gilbert static bool sdebug_clustering;
665773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
666773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
667817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
668773642d9SDouglas Gilbert static bool sdebug_verbose;
669f46eb0e9SDouglas Gilbert static bool have_dif_prot;
670c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
6711da177e4SLinus Torvalds 
672c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
6731da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
6741da177e4SLinus Torvalds 
6751da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
6761da177e4SLinus Torvalds    may still need them */
6771da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
6781da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
6791da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
6801da177e4SLinus Torvalds 
6811da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
6821da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
6831da177e4SLinus Torvalds 
6841da177e4SLinus Torvalds static unsigned char *fake_storep;	/* ramdisk storage */
6856ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_storep;	/* protection info */
68644d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
6871da177e4SLinus Torvalds 
68844d92694SMartin K. Petersen static unsigned long map_size;
689cbf67842SDouglas Gilbert static int num_aborts;
690cbf67842SDouglas Gilbert static int num_dev_resets;
691cbf67842SDouglas Gilbert static int num_target_resets;
692cbf67842SDouglas Gilbert static int num_bus_resets;
693cbf67842SDouglas Gilbert static int num_host_resets;
694c6a44287SMartin K. Petersen static int dix_writes;
695c6a44287SMartin K. Petersen static int dix_reads;
696c6a44287SMartin K. Petersen static int dif_errors;
6971da177e4SLinus Torvalds 
698c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
699c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
700fd32119bSDouglas Gilbert 
7011da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
7021da177e4SLinus Torvalds 
703cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
704cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
7051da177e4SLinus Torvalds 
7061da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
7071da177e4SLinus Torvalds 
7081da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
7091da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
7101da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
7111da177e4SLinus Torvalds };
7121da177e4SLinus Torvalds 
7131da177e4SLinus Torvalds static const int check_condition_result =
7141da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
7151da177e4SLinus Torvalds 
716c6a44287SMartin K. Petersen static const int illegal_condition_result =
717c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
718c6a44287SMartin K. Petersen 
719cbf67842SDouglas Gilbert static const int device_qfull_result =
720cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
721cbf67842SDouglas Gilbert 
722fd32119bSDouglas Gilbert 
723760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
724760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
725760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
726760f3b03SDouglas Gilbert  */
727760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
728fd32119bSDouglas Gilbert {
729fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
730fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
731fd32119bSDouglas Gilbert }
732c65b1445SDouglas Gilbert 
73314faa944SAkinobu Mita static void *fake_store(unsigned long long lba)
73414faa944SAkinobu Mita {
73514faa944SAkinobu Mita 	lba = do_div(lba, sdebug_store_sectors);
73614faa944SAkinobu Mita 
737773642d9SDouglas Gilbert 	return fake_storep + lba * sdebug_sector_size;
73814faa944SAkinobu Mita }
73914faa944SAkinobu Mita 
7406ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_store(sector_t sector)
74114faa944SAkinobu Mita {
74249413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
74314faa944SAkinobu Mita 
74414faa944SAkinobu Mita 	return dif_storep + sector;
74514faa944SAkinobu Mita }
74614faa944SAkinobu Mita 
7478dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
7488dea0d02SFUJITA Tomonori {
7498dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
7508dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
7518dea0d02SFUJITA Tomonori 
7528dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
7538dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
7548dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
7558dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
756773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
757773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
7588dea0d02SFUJITA Tomonori 		else
759773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
760773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
761f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
7628dea0d02SFUJITA Tomonori 	}
7638dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
7648dea0d02SFUJITA Tomonori }
7658dea0d02SFUJITA Tomonori 
76622017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
76722017ed2SDouglas Gilbert 
76822017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
769fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
770fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
77122017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
77222017ed2SDouglas Gilbert {
77322017ed2SDouglas Gilbert 	unsigned char *sbuff;
77422017ed2SDouglas Gilbert 	u8 sks[4];
77522017ed2SDouglas Gilbert 	int sl, asc;
77622017ed2SDouglas Gilbert 
77722017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
77822017ed2SDouglas Gilbert 	if (!sbuff) {
77922017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
78022017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
78122017ed2SDouglas Gilbert 		return;
78222017ed2SDouglas Gilbert 	}
78322017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
78422017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
785773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
78622017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
78722017ed2SDouglas Gilbert 	sks[0] = 0x80;
78822017ed2SDouglas Gilbert 	if (c_d)
78922017ed2SDouglas Gilbert 		sks[0] |= 0x40;
79022017ed2SDouglas Gilbert 	if (in_bit >= 0) {
79122017ed2SDouglas Gilbert 		sks[0] |= 0x8;
79222017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
79322017ed2SDouglas Gilbert 	}
79422017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
795773642d9SDouglas Gilbert 	if (sdebug_dsense) {
79622017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
79722017ed2SDouglas Gilbert 		sbuff[7] = sl;
79822017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
79922017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
80022017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
80122017ed2SDouglas Gilbert 	} else
80222017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
803773642d9SDouglas Gilbert 	if (sdebug_verbose)
80422017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
80522017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
80622017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
80722017ed2SDouglas Gilbert }
80822017ed2SDouglas Gilbert 
809cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
8108dea0d02SFUJITA Tomonori {
8118dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
8128dea0d02SFUJITA Tomonori 
813cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
814cbf67842SDouglas Gilbert 	if (!sbuff) {
815cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
816cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
817cbf67842SDouglas Gilbert 		return;
818cbf67842SDouglas Gilbert 	}
819cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
8208dea0d02SFUJITA Tomonori 
821773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
8228dea0d02SFUJITA Tomonori 
823773642d9SDouglas Gilbert 	if (sdebug_verbose)
824cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
825cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
826cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
8278dea0d02SFUJITA Tomonori }
8281da177e4SLinus Torvalds 
829fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
83022017ed2SDouglas Gilbert {
83122017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
83222017ed2SDouglas Gilbert }
83322017ed2SDouglas Gilbert 
8341da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
8351da177e4SLinus Torvalds {
836773642d9SDouglas Gilbert 	if (sdebug_verbose) {
837cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
838cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
839cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
840cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
841cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
842cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
843cbf67842SDouglas Gilbert 				    __func__);
844cbf67842SDouglas Gilbert 		else
845cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
846cbf67842SDouglas Gilbert 				    __func__, cmd);
8471da177e4SLinus Torvalds 	}
8481da177e4SLinus Torvalds 	return -EINVAL;
8491da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
8501da177e4SLinus Torvalds }
8511da177e4SLinus Torvalds 
8529b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
8539b760fd8SDouglas Gilbert {
8549b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
8559b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
8569b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8579b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8589b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8599b760fd8SDouglas Gilbert 		break;
8609b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
8619b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8629b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8639b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8649b760fd8SDouglas Gilbert 		break;
8659b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
8669b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8679b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8689b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8699b760fd8SDouglas Gilbert 		break;
8709b760fd8SDouglas Gilbert 	case 16:
8719b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8729b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
8739b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8749b760fd8SDouglas Gilbert 		break;
8759b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
8769b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8779b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
8789b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8799b760fd8SDouglas Gilbert 		break;
8809b760fd8SDouglas Gilbert 	default:
8819b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
8829b760fd8SDouglas Gilbert 			sdebug_cdb_len);
8839b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8849b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8859b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8869b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
8879b760fd8SDouglas Gilbert 		break;
8889b760fd8SDouglas Gilbert 	}
8899b760fd8SDouglas Gilbert }
8909b760fd8SDouglas Gilbert 
8919b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
8929b760fd8SDouglas Gilbert {
8939b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
8949b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
8959b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
8969b760fd8SDouglas Gilbert 
8979b760fd8SDouglas Gilbert 	spin_lock(&sdebug_host_list_lock);
8989b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
8999b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
9009b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
9019b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
9029b760fd8SDouglas Gilbert 		}
9039b760fd8SDouglas Gilbert 	}
9049b760fd8SDouglas Gilbert 	spin_unlock(&sdebug_host_list_lock);
9059b760fd8SDouglas Gilbert }
9069b760fd8SDouglas Gilbert 
90719c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
90819c8ead7SEwan D. Milne {
90919c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
91019c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
91119c8ead7SEwan D. Milne 
91219c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
91319c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
91419c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
91519c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
91619c8ead7SEwan D. Milne 			    (devip->target == dp->target))
91719c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
91819c8ead7SEwan D. Milne 		}
91919c8ead7SEwan D. Milne 	}
92019c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
92119c8ead7SEwan D. Milne }
92219c8ead7SEwan D. Milne 
923f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
9241da177e4SLinus Torvalds {
925cbf67842SDouglas Gilbert 	int k;
926cbf67842SDouglas Gilbert 
927cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
928cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
929cbf67842SDouglas Gilbert 		const char *cp = NULL;
930cbf67842SDouglas Gilbert 
931cbf67842SDouglas Gilbert 		switch (k) {
932cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
933f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
934f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
935773642d9SDouglas Gilbert 			if (sdebug_verbose)
936cbf67842SDouglas Gilbert 				cp = "power on reset";
937cbf67842SDouglas Gilbert 			break;
938cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
939f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
940f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
941773642d9SDouglas Gilbert 			if (sdebug_verbose)
942cbf67842SDouglas Gilbert 				cp = "bus reset";
943cbf67842SDouglas Gilbert 			break;
944cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
945f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
946f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
947773642d9SDouglas Gilbert 			if (sdebug_verbose)
948cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
949cbf67842SDouglas Gilbert 			break;
9500d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
951f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
952f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
953773642d9SDouglas Gilbert 			if (sdebug_verbose)
9540d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
955f49accf1SEwan D. Milne 			break;
956acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
957f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
958b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
959b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
960773642d9SDouglas Gilbert 			if (sdebug_verbose)
961acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
962acafd0b9SEwan D. Milne 			break;
963acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
964f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
965acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
966acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
967773642d9SDouglas Gilbert 			if (sdebug_verbose)
968acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
969acafd0b9SEwan D. Milne 			break;
97019c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
97119c8ead7SEwan D. Milne 			/*
97219c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
97319c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
97419c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
97519c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
976773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
97719c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
97819c8ead7SEwan D. Milne 			 */
979773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
98019c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
981f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
98219c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
98319c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
984773642d9SDouglas Gilbert 			if (sdebug_verbose)
98519c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
98619c8ead7SEwan D. Milne 			break;
987cbf67842SDouglas Gilbert 		default:
988773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
989773642d9SDouglas Gilbert 			if (sdebug_verbose)
990cbf67842SDouglas Gilbert 				cp = "unknown";
991cbf67842SDouglas Gilbert 			break;
992cbf67842SDouglas Gilbert 		}
993cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
994773642d9SDouglas Gilbert 		if (sdebug_verbose)
995f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
996cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
997cbf67842SDouglas Gilbert 				   my_name, cp);
9981da177e4SLinus Torvalds 		return check_condition_result;
9991da177e4SLinus Torvalds 	}
10001da177e4SLinus Torvalds 	return 0;
10011da177e4SLinus Torvalds }
10021da177e4SLinus Torvalds 
1003fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
10041da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
10051da177e4SLinus Torvalds 				int arr_len)
10061da177e4SLinus Torvalds {
100721a61829SFUJITA Tomonori 	int act_len;
1008072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
10091da177e4SLinus Torvalds 
1010072d0bb3SFUJITA Tomonori 	if (!sdb->length)
10111da177e4SLinus Torvalds 		return 0;
1012072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
1013773642d9SDouglas Gilbert 		return DID_ERROR << 16;
101421a61829SFUJITA Tomonori 
101521a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
101621a61829SFUJITA Tomonori 				      arr, arr_len);
101721a61829SFUJITA Tomonori 	sdb->resid = scsi_bufflen(scp) - act_len;
101821a61829SFUJITA Tomonori 
10191da177e4SLinus Torvalds 	return 0;
10201da177e4SLinus Torvalds }
10211da177e4SLinus Torvalds 
1022fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1023fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1024fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
1025fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
1026fb0cc8d1SDouglas Gilbert  */
1027fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1028fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
1029fb0cc8d1SDouglas Gilbert {
1030fb0cc8d1SDouglas Gilbert 	int act_len, n;
1031fb0cc8d1SDouglas Gilbert 	struct scsi_data_buffer *sdb = scsi_in(scp);
1032fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
1033fb0cc8d1SDouglas Gilbert 
1034fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
1035fb0cc8d1SDouglas Gilbert 		return 0;
1036fb0cc8d1SDouglas Gilbert 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
1037fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
1038fb0cc8d1SDouglas Gilbert 
1039fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1040fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
1041fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
1042fb0cc8d1SDouglas Gilbert 		 __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid);
1043fb0cc8d1SDouglas Gilbert 	n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
1044fb0cc8d1SDouglas Gilbert 	sdb->resid = min(sdb->resid, n);
1045fb0cc8d1SDouglas Gilbert 	return 0;
1046fb0cc8d1SDouglas Gilbert }
1047fb0cc8d1SDouglas Gilbert 
1048fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1049fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1050fb0cc8d1SDouglas Gilbert  */
10511da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
105221a61829SFUJITA Tomonori 			       int arr_len)
10531da177e4SLinus Torvalds {
105421a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
10551da177e4SLinus Torvalds 		return 0;
1056072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
10571da177e4SLinus Torvalds 		return -1;
105821a61829SFUJITA Tomonori 
105921a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
10601da177e4SLinus Torvalds }
10611da177e4SLinus Torvalds 
10621da177e4SLinus Torvalds 
1063e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1064e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
10659b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
10661b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
10671b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
10681b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
10691b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
10701da177e4SLinus Torvalds 
1071cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
1072760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
10735a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
107409ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1075bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
10761da177e4SLinus Torvalds {
1077c65b1445SDouglas Gilbert 	int num, port_a;
1078c65b1445SDouglas Gilbert 	char b[32];
10791da177e4SLinus Torvalds 
1080c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
10811da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
10821da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
10831da177e4SLinus Torvalds 	arr[1] = 0x1;
10841da177e4SLinus Torvalds 	arr[2] = 0x0;
1085e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1086e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
10871da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
10881da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
10891da177e4SLinus Torvalds 	arr[3] = num;
10901da177e4SLinus Torvalds 	num += 4;
1091c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
109209ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
109309ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
109409ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
109509ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
109609ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
109709ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
109809ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
109909ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
110009ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
110109ba24c1SDouglas Gilbert 			num += 16;
110209ba24c1SDouglas Gilbert 		} else {
11031b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1104c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1105c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1106c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1107c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
11081b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1109773642d9SDouglas Gilbert 			num += 8;
111009ba24c1SDouglas Gilbert 		}
1111c65b1445SDouglas Gilbert 		/* Target relative port number */
1112c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1113c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1114c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1115c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1116c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1117c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1118c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1119c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1120c65b1445SDouglas Gilbert 	}
11211b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1122c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1123c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1124c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1125c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
11261b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1127773642d9SDouglas Gilbert 	num += 8;
11281b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
11295a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
11305a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
11315a09e398SHannes Reinecke 	arr[num++] = 0x0;
11325a09e398SHannes Reinecke 	arr[num++] = 0x4;
11335a09e398SHannes Reinecke 	arr[num++] = 0;
11345a09e398SHannes Reinecke 	arr[num++] = 0;
1135773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1136773642d9SDouglas Gilbert 	num += 2;
11371b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1138c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1139c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1140c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1141c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
11421b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1143773642d9SDouglas Gilbert 	num += 8;
1144c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1145c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1146c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1147c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1148c65b1445SDouglas Gilbert 	arr[num++] = 24;
11491b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1150c65b1445SDouglas Gilbert 	num += 12;
1151c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1152c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1153c65b1445SDouglas Gilbert 	num += 8;
1154c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1155c65b1445SDouglas Gilbert 	num += 4;
1156c65b1445SDouglas Gilbert 	return num;
1157c65b1445SDouglas Gilbert }
1158c65b1445SDouglas Gilbert 
1159c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1160c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1161c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1162c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1163c65b1445SDouglas Gilbert };
1164c65b1445SDouglas Gilbert 
1165cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1166760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1167c65b1445SDouglas Gilbert {
1168c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1169c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1170c65b1445SDouglas Gilbert }
1171c65b1445SDouglas Gilbert 
1172cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1173760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1174c65b1445SDouglas Gilbert {
1175c65b1445SDouglas Gilbert 	int num = 0;
1176c65b1445SDouglas Gilbert 	const char *na1 = "https://www.kernel.org/config";
1177c65b1445SDouglas Gilbert 	const char *na2 = "http://www.kernel.org/log";
1178c65b1445SDouglas Gilbert 	int plen, olen;
1179c65b1445SDouglas Gilbert 
1180c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1181c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1182c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1183c65b1445SDouglas Gilbert 	olen = strlen(na1);
1184c65b1445SDouglas Gilbert 	plen = olen + 1;
1185c65b1445SDouglas Gilbert 	if (plen % 4)
1186c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1187c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1188c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1189c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1190c65b1445SDouglas Gilbert 	num += plen;
1191c65b1445SDouglas Gilbert 
1192c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1193c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1194c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1195c65b1445SDouglas Gilbert 	olen = strlen(na2);
1196c65b1445SDouglas Gilbert 	plen = olen + 1;
1197c65b1445SDouglas Gilbert 	if (plen % 4)
1198c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1199c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1200c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1201c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1202c65b1445SDouglas Gilbert 	num += plen;
1203c65b1445SDouglas Gilbert 
1204c65b1445SDouglas Gilbert 	return num;
1205c65b1445SDouglas Gilbert }
1206c65b1445SDouglas Gilbert 
1207c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1208760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1209c65b1445SDouglas Gilbert {
1210c65b1445SDouglas Gilbert 	int num = 0;
1211c65b1445SDouglas Gilbert 	int port_a, port_b;
1212c65b1445SDouglas Gilbert 
1213c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1214c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1215c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1216c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1217c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1218c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1219c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1220c65b1445SDouglas Gilbert 	num += 6;
1221c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1222c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1223c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1224c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1225c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1226c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1227c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
12281b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1229773642d9SDouglas Gilbert 	num += 8;
1230c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1231c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1232c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1233c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1234c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1235c65b1445SDouglas Gilbert 	num += 6;
1236c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1237c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1238c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1239c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1240c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1241c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1242c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
12431b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1244773642d9SDouglas Gilbert 	num += 8;
1245c65b1445SDouglas Gilbert 
1246c65b1445SDouglas Gilbert 	return num;
1247c65b1445SDouglas Gilbert }
1248c65b1445SDouglas Gilbert 
1249c65b1445SDouglas Gilbert 
1250c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1251c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1252c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1253c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1254c65b1445SDouglas Gilbert '1','2','3','4',
1255c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1256c65b1445SDouglas Gilbert 0xec,0,0,0,
1257c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1258c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1259c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1260c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1261c65b1445SDouglas Gilbert 0x53,0x41,
1262c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1263c65b1445SDouglas Gilbert 0x20,0x20,
1264c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1265c65b1445SDouglas Gilbert 0x10,0x80,
1266c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1267c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1268c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1269c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1270c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1271c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1272c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1273c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1274c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1275c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1276c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1277c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1278c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1279c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1280c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1281c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1282c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1283c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1284c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1285c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1286c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1287c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1288c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1289c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1290c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1291c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1292c65b1445SDouglas Gilbert };
1293c65b1445SDouglas Gilbert 
1294cbf67842SDouglas Gilbert /* ATA Information VPD page */
1295760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1296c65b1445SDouglas Gilbert {
1297c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1298c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1299c65b1445SDouglas Gilbert }
1300c65b1445SDouglas Gilbert 
1301c65b1445SDouglas Gilbert 
1302c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
13031e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
13041e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
13051e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
13061e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1307c65b1445SDouglas Gilbert };
1308c65b1445SDouglas Gilbert 
1309cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1310760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1311c65b1445SDouglas Gilbert {
1312ea61fca5SMartin K. Petersen 	unsigned int gran;
1313ea61fca5SMartin K. Petersen 
1314c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1315e308b3d1SMartin K. Petersen 
1316e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
131786e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
131886e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
131986e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
132086e6828aSLukas Herbolt 	else
1321773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1322773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1323e308b3d1SMartin K. Petersen 
1324e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1325773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1326773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
132744d92694SMartin K. Petersen 
1328e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1329773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1330e308b3d1SMartin K. Petersen 
1331773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1332e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1333773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1334e308b3d1SMartin K. Petersen 
1335e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1336773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
133744d92694SMartin K. Petersen 	}
133844d92694SMartin K. Petersen 
1339e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1340773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1341773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
134244d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
134344d92694SMartin K. Petersen 	}
134444d92694SMartin K. Petersen 
1345e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1346773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
13476014759cSMartin K. Petersen 
13485b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1349773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
13505b94e232SMartin K. Petersen 
13515b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
135244d92694SMartin K. Petersen 
1353c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
13541da177e4SLinus Torvalds }
13551da177e4SLinus Torvalds 
13561e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
1357760f3b03SDouglas Gilbert static int inquiry_vpd_b1(unsigned char *arr)
1358eac6e8e4SMatthew Wilcox {
1359eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1360eac6e8e4SMatthew Wilcox 	arr[0] = 0;
13611e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
13621e49f785SDouglas Gilbert 	arr[2] = 0;
13631e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
1364eac6e8e4SMatthew Wilcox 
1365eac6e8e4SMatthew Wilcox 	return 0x3c;
1366eac6e8e4SMatthew Wilcox }
13671da177e4SLinus Torvalds 
1368760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1369760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
13706014759cSMartin K. Petersen {
13713f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
13726014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1373773642d9SDouglas Gilbert 	if (sdebug_lbpu)
13746014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1375773642d9SDouglas Gilbert 	if (sdebug_lbpws)
13766014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1377773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
13785b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1379760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1380760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1381760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1382760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1383760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
13843f0bc3b3SMartin K. Petersen 	return 0x4;
13856014759cSMartin K. Petersen }
13866014759cSMartin K. Petersen 
13871da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1388c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
13891da177e4SLinus Torvalds 
1390c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
13911da177e4SLinus Torvalds {
13921da177e4SLinus Torvalds 	unsigned char pq_pdt;
13935a09e398SHannes Reinecke 	unsigned char *arr;
139401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
13955a09e398SHannes Reinecke 	int alloc_len, n, ret;
1396760f3b03SDouglas Gilbert 	bool have_wlun, is_disk;
13971da177e4SLinus Torvalds 
1398773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
13996f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
14006f3cbf55SDouglas Gilbert 	if (! arr)
14016f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1402760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
1403b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1404c2248fc9SDouglas Gilbert 	if (have_wlun)
1405b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1406b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1407b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1408c65b1445SDouglas Gilbert 	else
1409773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
14101da177e4SLinus Torvalds 	arr[0] = pq_pdt;
14111da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
141222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
14135a09e398SHannes Reinecke 		kfree(arr);
14141da177e4SLinus Torvalds 		return check_condition_result;
14151da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
14165a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1417c65b1445SDouglas Gilbert 		char lu_id_str[6];
1418c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
14191da177e4SLinus Torvalds 
14205a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
14215a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1422b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
142323183910SDouglas Gilbert 			host_no = 0;
1424c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1425c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1426c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1427c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1428c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
14291da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1430c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1431c65b1445SDouglas Gilbert 			n = 4;
1432c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1433c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1434c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1435c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1436c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1437c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1438c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1439c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1440760f3b03SDouglas Gilbert 			if (is_disk) {	  /* SBC only */
1441c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1442760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1443760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1444760f3b03SDouglas Gilbert 				arr[n++] = 0xb2;  /* Logical Block Prov */
1445760f3b03SDouglas Gilbert 			}
1446c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
14471da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1448c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
14491da177e4SLinus Torvalds 			arr[3] = len;
1450c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
14511da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1452c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1453760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
14545a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
145509ba24c1SDouglas Gilbert 						lu_id_str, len,
145609ba24c1SDouglas Gilbert 						&devip->lu_name);
1457c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1458c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1459760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1460c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1461c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1462760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1463c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1464c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1465c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
14668475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1467c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1468760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1469c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1470c6a44287SMartin K. Petersen 			else
1471c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1472c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1473c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1474c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1475c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1476c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1477c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1478c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1479c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1480c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1481c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1482760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1483760f3b03SDouglas Gilbert 		} else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
1484c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1485760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1486773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1487760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
1488c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1489760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1490760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
1491eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
1492760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b1(&arr[4]);
1493760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
14946014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1495760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
14961da177e4SLinus Torvalds 		} else {
149722017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
14985a09e398SHannes Reinecke 			kfree(arr);
14991da177e4SLinus Torvalds 			return check_condition_result;
15001da177e4SLinus Torvalds 		}
1501773642d9SDouglas Gilbert 		len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
15025a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1503c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
15045a09e398SHannes Reinecke 		kfree(arr);
15055a09e398SHannes Reinecke 		return ret;
15061da177e4SLinus Torvalds 	}
15071da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1508773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1509773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
15101da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
15111da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1512f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1513b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
151470bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1515c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
15161da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1517c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1518e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1519e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1520e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
15219b760fd8SDouglas Gilbert 	/* Use Vendor Specific area to place driver date in ASCII hex */
15229b760fd8SDouglas Gilbert 	memcpy(&arr[36], sdebug_version_date, 8);
15231da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1524760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1525760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1526c65b1445SDouglas Gilbert 	n = 62;
1527760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1528760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1529760f3b03SDouglas Gilbert 		n += 2;
1530760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1531760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1532760f3b03SDouglas Gilbert 		n += 2;
15331da177e4SLinus Torvalds 	}
1534760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
15355a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
15361da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
15375a09e398SHannes Reinecke 	kfree(arr);
15385a09e398SHannes Reinecke 	return ret;
15391da177e4SLinus Torvalds }
15401da177e4SLinus Torvalds 
1541fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1542fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1543fd32119bSDouglas Gilbert 
15441da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp,
15451da177e4SLinus Torvalds 			 struct sdebug_dev_info *devip)
15461da177e4SLinus Torvalds {
15471da177e4SLinus Torvalds 	unsigned char *sbuff;
154801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1549cbf67842SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
15502492fc09STomas Winkler 	bool dsense;
15511da177e4SLinus Torvalds 	int len = 18;
15521da177e4SLinus Torvalds 
1553c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1554c2248fc9SDouglas Gilbert 	dsense = !!(cmd[1] & 1);
1555cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
1556c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1557c2248fc9SDouglas Gilbert 		if (dsense) {
1558c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1559c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1560c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
1561c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
1562c2248fc9SDouglas Gilbert 			len = 8;
1563c65b1445SDouglas Gilbert 		} else {
1564c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1565c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1566c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1567c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
1568c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
1569c65b1445SDouglas Gilbert 		}
1570c65b1445SDouglas Gilbert 	} else {
1571cbf67842SDouglas Gilbert 		memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
1572773642d9SDouglas Gilbert 		if (arr[0] >= 0x70 && dsense == sdebug_dsense)
1573c2248fc9SDouglas Gilbert 			;	/* have sense and formats match */
1574c2248fc9SDouglas Gilbert 		else if (arr[0] <= 0x70) {
1575c2248fc9SDouglas Gilbert 			if (dsense) {
1576c2248fc9SDouglas Gilbert 				memset(arr, 0, 8);
1577c2248fc9SDouglas Gilbert 				arr[0] = 0x72;
1578c2248fc9SDouglas Gilbert 				len = 8;
1579c2248fc9SDouglas Gilbert 			} else {
1580c2248fc9SDouglas Gilbert 				memset(arr, 0, 18);
1581c2248fc9SDouglas Gilbert 				arr[0] = 0x70;
1582c2248fc9SDouglas Gilbert 				arr[7] = 0xa;
1583c2248fc9SDouglas Gilbert 			}
1584c2248fc9SDouglas Gilbert 		} else if (dsense) {
1585c2248fc9SDouglas Gilbert 			memset(arr, 0, 8);
15861da177e4SLinus Torvalds 			arr[0] = 0x72;
15871da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
15881da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
15891da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
15901da177e4SLinus Torvalds 			len = 8;
1591c2248fc9SDouglas Gilbert 		} else {
1592c2248fc9SDouglas Gilbert 			memset(arr, 0, 18);
1593c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1594c2248fc9SDouglas Gilbert 			arr[2] = sbuff[1];
1595c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1596c2248fc9SDouglas Gilbert 			arr[12] = sbuff[1];
1597c2248fc9SDouglas Gilbert 			arr[13] = sbuff[3];
1598c65b1445SDouglas Gilbert 		}
1599c2248fc9SDouglas Gilbert 
1600c65b1445SDouglas Gilbert 	}
1601cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
16021da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
16031da177e4SLinus Torvalds }
16041da177e4SLinus Torvalds 
1605c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp,
1606c65b1445SDouglas Gilbert 			   struct sdebug_dev_info *devip)
1607c65b1445SDouglas Gilbert {
160801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1609c4837394SDouglas Gilbert 	int power_cond, stop;
1610c65b1445SDouglas Gilbert 
1611c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1612c65b1445SDouglas Gilbert 	if (power_cond) {
161322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1614c65b1445SDouglas Gilbert 		return check_condition_result;
1615c65b1445SDouglas Gilbert 	}
1616c4837394SDouglas Gilbert 	stop = !(cmd[4] & 1);
1617c4837394SDouglas Gilbert 	atomic_xchg(&devip->stopped, stop);
161880c49563SDouglas Gilbert 	return (cmd[1] & 0x1) ? SDEG_RES_IMMED_MASK : 0; /* check IMMED bit */
1619c65b1445SDouglas Gilbert }
1620c65b1445SDouglas Gilbert 
162128898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
162228898873SFUJITA Tomonori {
1623773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1624773642d9SDouglas Gilbert 
1625773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1626773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1627773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
162828898873SFUJITA Tomonori 	else
162928898873SFUJITA Tomonori 		return sdebug_store_sectors;
163028898873SFUJITA Tomonori }
163128898873SFUJITA Tomonori 
16321da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
16331da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp,
16341da177e4SLinus Torvalds 			struct sdebug_dev_info *devip)
16351da177e4SLinus Torvalds {
16361da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1637c65b1445SDouglas Gilbert 	unsigned int capac;
16381da177e4SLinus Torvalds 
1639c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
164028898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
16411da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1642c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1643c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1644773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1645773642d9SDouglas Gilbert 	} else
1646773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1647773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
16481da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
16491da177e4SLinus Torvalds }
16501da177e4SLinus Torvalds 
1651c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1652c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp,
1653c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
1654c65b1445SDouglas Gilbert {
165501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1656c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1657773642d9SDouglas Gilbert 	int alloc_len;
1658c65b1445SDouglas Gilbert 
1659773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1660c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
166128898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1662c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1663773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1664773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1665773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1666773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
166744d92694SMartin K. Petersen 
1668be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
16695b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1670760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1671760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1672760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1673760f3b03SDouglas Gilbert 		 */
1674760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1675760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1676be1dd78dSEric Sandeen 	}
167744d92694SMartin K. Petersen 
1678773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1679c6a44287SMartin K. Petersen 
1680760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1681773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1682c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1683c6a44287SMartin K. Petersen 	}
1684c6a44287SMartin K. Petersen 
1685c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1686c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1687c65b1445SDouglas Gilbert }
1688c65b1445SDouglas Gilbert 
16895a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
16905a09e398SHannes Reinecke 
16915a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp,
16925a09e398SHannes Reinecke 			      struct sdebug_dev_info *devip)
16935a09e398SHannes Reinecke {
169401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
16955a09e398SHannes Reinecke 	unsigned char *arr;
16965a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
16975a09e398SHannes Reinecke 	int n, ret, alen, rlen;
16985a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
16995a09e398SHannes Reinecke 
1700773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
17016f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
17026f3cbf55SDouglas Gilbert 	if (! arr)
17036f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
17045a09e398SHannes Reinecke 	/*
17055a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
17065a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
17075a09e398SHannes Reinecke 	 * So we create two port groups with one port each
17085a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
17095a09e398SHannes Reinecke 	 */
17105a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
17115a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
17125a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
17135a09e398SHannes Reinecke 			(devip->channel & 0x7f);
17145a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
17155a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
17165a09e398SHannes Reinecke 
17175a09e398SHannes Reinecke 	/*
17185a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
17195a09e398SHannes Reinecke 	 */
17205a09e398SHannes Reinecke 	n = 4;
1721b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
17225a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
17235a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
17245a09e398SHannes Reinecke 	} else {
17255a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1726773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
17275a09e398SHannes Reinecke 	}
1728773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1729773642d9SDouglas Gilbert 	n += 2;
17305a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17315a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
17325a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
17335a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
17345a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17355a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1736773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1737773642d9SDouglas Gilbert 	n += 2;
17385a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
17395a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1740773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1741773642d9SDouglas Gilbert 	n += 2;
17425a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17435a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
17445a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
17455a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
17465a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17475a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1748773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1749773642d9SDouglas Gilbert 	n += 2;
17505a09e398SHannes Reinecke 
17515a09e398SHannes Reinecke 	rlen = n - 4;
1752773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
17535a09e398SHannes Reinecke 
17545a09e398SHannes Reinecke 	/*
17555a09e398SHannes Reinecke 	 * Return the smallest value of either
17565a09e398SHannes Reinecke 	 * - The allocated length
17575a09e398SHannes Reinecke 	 * - The constructed command length
17585a09e398SHannes Reinecke 	 * - The maximum array size
17595a09e398SHannes Reinecke 	 */
17605a09e398SHannes Reinecke 	rlen = min(alen,n);
17615a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
17625a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
17635a09e398SHannes Reinecke 	kfree(arr);
17645a09e398SHannes Reinecke 	return ret;
17655a09e398SHannes Reinecke }
17665a09e398SHannes Reinecke 
1767fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1768fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
176938d5c833SDouglas Gilbert {
177038d5c833SDouglas Gilbert 	bool rctd;
177138d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
177238d5c833SDouglas Gilbert 	u16 req_sa, u;
177338d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
177438d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
177538d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
177638d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
177738d5c833SDouglas Gilbert 	u8 *arr;
177838d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
177938d5c833SDouglas Gilbert 
178038d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
178138d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
178238d5c833SDouglas Gilbert 	req_opcode = cmd[3];
178338d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
178438d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
17856d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
178638d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
178738d5c833SDouglas Gilbert 		return check_condition_result;
178838d5c833SDouglas Gilbert 	}
178938d5c833SDouglas Gilbert 	if (alloc_len > 8192)
179038d5c833SDouglas Gilbert 		a_len = 8192;
179138d5c833SDouglas Gilbert 	else
179238d5c833SDouglas Gilbert 		a_len = alloc_len;
179399531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
179438d5c833SDouglas Gilbert 	if (NULL == arr) {
179538d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
179638d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
179738d5c833SDouglas Gilbert 		return check_condition_result;
179838d5c833SDouglas Gilbert 	}
179938d5c833SDouglas Gilbert 	switch (reporting_opts) {
180038d5c833SDouglas Gilbert 	case 0:	/* all commands */
180138d5c833SDouglas Gilbert 		/* count number of commands */
180238d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
180338d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
180438d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
180538d5c833SDouglas Gilbert 				continue;
180638d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
180738d5c833SDouglas Gilbert 		}
180838d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
180938d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
181038d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
181138d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
181238d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
181338d5c833SDouglas Gilbert 				continue;
181438d5c833SDouglas Gilbert 			na = oip->num_attached;
181538d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
181638d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
181738d5c833SDouglas Gilbert 			if (rctd)
181838d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
181938d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
182038d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
182138d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
182238d5c833SDouglas Gilbert 			if (rctd)
182338d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
182438d5c833SDouglas Gilbert 			r_oip = oip;
182538d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
182638d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
182738d5c833SDouglas Gilbert 					continue;
182838d5c833SDouglas Gilbert 				offset += bump;
182938d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
183038d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
183138d5c833SDouglas Gilbert 				if (rctd)
183238d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
183338d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
183438d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
183538d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
183638d5c833SDouglas Gilbert 						   arr + offset + 6);
183738d5c833SDouglas Gilbert 				if (rctd)
183838d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
183938d5c833SDouglas Gilbert 							   arr + offset + 8);
184038d5c833SDouglas Gilbert 			}
184138d5c833SDouglas Gilbert 			oip = r_oip;
184238d5c833SDouglas Gilbert 			offset += bump;
184338d5c833SDouglas Gilbert 		}
184438d5c833SDouglas Gilbert 		break;
184538d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
184638d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
184738d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
184838d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
184938d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
185038d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
185138d5c833SDouglas Gilbert 			supp = 1;
185238d5c833SDouglas Gilbert 			offset = 4;
185338d5c833SDouglas Gilbert 		} else {
185438d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
185538d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
185638d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
185738d5c833SDouglas Gilbert 							     2, 2);
185838d5c833SDouglas Gilbert 					kfree(arr);
185938d5c833SDouglas Gilbert 					return check_condition_result;
186038d5c833SDouglas Gilbert 				}
186138d5c833SDouglas Gilbert 				req_sa = 0;
186238d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
186338d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
186438d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
186538d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
186638d5c833SDouglas Gilbert 				return check_condition_result;
186738d5c833SDouglas Gilbert 			}
186838d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
186938d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
187038d5c833SDouglas Gilbert 				supp = 3;
187138d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
187238d5c833SDouglas Gilbert 				na = oip->num_attached;
187338d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
187438d5c833SDouglas Gilbert 				     ++k, ++oip) {
187538d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
187638d5c833SDouglas Gilbert 						break;
187738d5c833SDouglas Gilbert 				}
187838d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
187938d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
188038d5c833SDouglas Gilbert 				na = oip->num_attached;
188138d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
188238d5c833SDouglas Gilbert 				     ++k, ++oip) {
188338d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
188438d5c833SDouglas Gilbert 						break;
188538d5c833SDouglas Gilbert 				}
188638d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
188738d5c833SDouglas Gilbert 			} else
188838d5c833SDouglas Gilbert 				supp = 3;
188938d5c833SDouglas Gilbert 			if (3 == supp) {
189038d5c833SDouglas Gilbert 				u = oip->len_mask[0];
189138d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
189238d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
189338d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
189438d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
189538d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
189638d5c833SDouglas Gilbert 				offset = 4 + u;
189738d5c833SDouglas Gilbert 			} else
189838d5c833SDouglas Gilbert 				offset = 4;
189938d5c833SDouglas Gilbert 		}
190038d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
190138d5c833SDouglas Gilbert 		if (rctd) {
190238d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
190338d5c833SDouglas Gilbert 			offset += 12;
190438d5c833SDouglas Gilbert 		}
190538d5c833SDouglas Gilbert 		break;
190638d5c833SDouglas Gilbert 	default:
190738d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
190838d5c833SDouglas Gilbert 		kfree(arr);
190938d5c833SDouglas Gilbert 		return check_condition_result;
191038d5c833SDouglas Gilbert 	}
191138d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
191238d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
191338d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
191438d5c833SDouglas Gilbert 	kfree(arr);
191538d5c833SDouglas Gilbert 	return errsts;
191638d5c833SDouglas Gilbert }
191738d5c833SDouglas Gilbert 
1918fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1919fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
192038d5c833SDouglas Gilbert {
192138d5c833SDouglas Gilbert 	bool repd;
192238d5c833SDouglas Gilbert 	u32 alloc_len, len;
192338d5c833SDouglas Gilbert 	u8 arr[16];
192438d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
192538d5c833SDouglas Gilbert 
192638d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
192738d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
192838d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
192938d5c833SDouglas Gilbert 	if (alloc_len < 4) {
193038d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
193138d5c833SDouglas Gilbert 		return check_condition_result;
193238d5c833SDouglas Gilbert 	}
193338d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
193438d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
193538d5c833SDouglas Gilbert 	if (repd) {
193638d5c833SDouglas Gilbert 		arr[3] = 0xc;
193738d5c833SDouglas Gilbert 		len = 16;
193838d5c833SDouglas Gilbert 	} else
193938d5c833SDouglas Gilbert 		len = 4;
194038d5c833SDouglas Gilbert 
194138d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
194238d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
194338d5c833SDouglas Gilbert }
194438d5c833SDouglas Gilbert 
19451da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
19461da177e4SLinus Torvalds 
19471da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
19481da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
19491da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
19501da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
19511da177e4SLinus Torvalds 
19521da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
19531da177e4SLinus Torvalds 	if (1 == pcontrol)
19541da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
19551da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
19561da177e4SLinus Torvalds }
19571da177e4SLinus Torvalds 
19581da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
19591da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
19601da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
19611da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
19621da177e4SLinus Torvalds 
19631da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
19641da177e4SLinus Torvalds 	if (1 == pcontrol)
19651da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
19661da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
19671da177e4SLinus Torvalds }
19681da177e4SLinus Torvalds 
19691da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target)
19701da177e4SLinus Torvalds {       /* Format device page for mode_sense */
19711da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
19721da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
19731da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
19741da177e4SLinus Torvalds 
19751da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
1976773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
1977773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
1978773642d9SDouglas Gilbert 	if (sdebug_removable)
19791da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
19801da177e4SLinus Torvalds 	if (1 == pcontrol)
19811da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
19821da177e4SLinus Torvalds 	return sizeof(format_pg);
19831da177e4SLinus Torvalds }
19841da177e4SLinus Torvalds 
1985fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1986fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1987fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
1988fd32119bSDouglas Gilbert 
19891da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
19901da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
1991cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1992cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1993cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
19941da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
19951da177e4SLinus Torvalds 
1996773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
1997cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
19981da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
19991da177e4SLinus Torvalds 	if (1 == pcontrol)
2000cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2001cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
2002cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
20031da177e4SLinus Torvalds 	return sizeof(caching_pg);
20041da177e4SLinus Torvalds }
20051da177e4SLinus Torvalds 
2006fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2007fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
2008fd32119bSDouglas Gilbert 
20091da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
20101da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
2011c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
2012c65b1445SDouglas Gilbert 					0, 0, 0, 0};
2013c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
20141da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
20151da177e4SLinus Torvalds 
2016773642d9SDouglas Gilbert 	if (sdebug_dsense)
20171da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
2018c65b1445SDouglas Gilbert 	else
2019c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
2020c6a44287SMartin K. Petersen 
2021773642d9SDouglas Gilbert 	if (sdebug_ato)
2022c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2023c6a44287SMartin K. Petersen 
20241da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
20251da177e4SLinus Torvalds 	if (1 == pcontrol)
2026c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2027c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2028c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
20291da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
20301da177e4SLinus Torvalds }
20311da177e4SLinus Torvalds 
2032c65b1445SDouglas Gilbert 
20331da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
20341da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2035c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
20361da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2037c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2038c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2039c65b1445SDouglas Gilbert 
20401da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
20411da177e4SLinus Torvalds 	if (1 == pcontrol)
2042c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2043c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2044c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
20451da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
20461da177e4SLinus Torvalds }
20471da177e4SLinus Torvalds 
2048c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
2049c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2050c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2051c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2052c65b1445SDouglas Gilbert 
2053c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2054c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2055c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2056c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2057c65b1445SDouglas Gilbert }
2058c65b1445SDouglas Gilbert 
2059c65b1445SDouglas Gilbert 
2060c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
2061c65b1445SDouglas Gilbert 			      int target_dev_id)
2062c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2063c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2064c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2065773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2066773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2067c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2068c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2069c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2070c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2071773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2072773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2073c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2074c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2075c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2076c65b1445SDouglas Gilbert 		};
2077c65b1445SDouglas Gilbert 	int port_a, port_b;
2078c65b1445SDouglas Gilbert 
20791b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
20801b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
20811b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
20821b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2083c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2084c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2085c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2086773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2087773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2088c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2089c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2090c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2091c65b1445SDouglas Gilbert }
2092c65b1445SDouglas Gilbert 
2093c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
2094c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2095c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2096c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2097c65b1445SDouglas Gilbert 		};
2098c65b1445SDouglas Gilbert 
2099c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2100c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2101c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2102c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2103c65b1445SDouglas Gilbert }
2104c65b1445SDouglas Gilbert 
21051da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
21061da177e4SLinus Torvalds 
2107fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2108fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
21091da177e4SLinus Torvalds {
211023183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
21111da177e4SLinus Torvalds 	unsigned char dev_spec;
2112760f3b03SDouglas Gilbert 	int alloc_len, offset, len, target_dev_id;
2113c2248fc9SDouglas Gilbert 	int target = scp->device->id;
21141da177e4SLinus Torvalds 	unsigned char *ap;
21151da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
211601123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2117760f3b03SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, bad_pcode;
21181da177e4SLinus Torvalds 
2119760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
21201da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
21211da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
21221da177e4SLinus Torvalds 	subpcode = cmd[3];
21231da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2124760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2125760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
2126760f3b03SDouglas Gilbert 	if (is_disk && !dbd)
212723183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
212823183910SDouglas Gilbert 	else
212923183910SDouglas Gilbert 		bd_len = 0;
2130773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
21311da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
21321da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2133cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
21341da177e4SLinus Torvalds 		return check_condition_result;
21351da177e4SLinus Torvalds 	}
2136c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2137c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2138b01f6f83SDouglas Gilbert 	/* for disks set DPOFUA bit and clear write protect (WP) bit */
2139760f3b03SDouglas Gilbert 	if (is_disk)
2140b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
214123183910SDouglas Gilbert 	else
214223183910SDouglas Gilbert 		dev_spec = 0x0;
21431da177e4SLinus Torvalds 	if (msense_6) {
21441da177e4SLinus Torvalds 		arr[2] = dev_spec;
214523183910SDouglas Gilbert 		arr[3] = bd_len;
21461da177e4SLinus Torvalds 		offset = 4;
21471da177e4SLinus Torvalds 	} else {
21481da177e4SLinus Torvalds 		arr[3] = dev_spec;
214923183910SDouglas Gilbert 		if (16 == bd_len)
215023183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
215123183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
21521da177e4SLinus Torvalds 		offset = 8;
21531da177e4SLinus Torvalds 	}
21541da177e4SLinus Torvalds 	ap = arr + offset;
215528898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
215628898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
215728898873SFUJITA Tomonori 
215823183910SDouglas Gilbert 	if (8 == bd_len) {
2159773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2160773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2161773642d9SDouglas Gilbert 		else
2162773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2163773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
216423183910SDouglas Gilbert 		offset += bd_len;
216523183910SDouglas Gilbert 		ap = arr + offset;
216623183910SDouglas Gilbert 	} else if (16 == bd_len) {
2167773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2168773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
216923183910SDouglas Gilbert 		offset += bd_len;
217023183910SDouglas Gilbert 		ap = arr + offset;
217123183910SDouglas Gilbert 	}
21721da177e4SLinus Torvalds 
2173c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2174c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
217522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
21761da177e4SLinus Torvalds 		return check_condition_result;
21771da177e4SLinus Torvalds 	}
2178760f3b03SDouglas Gilbert 	bad_pcode = false;
2179760f3b03SDouglas Gilbert 
21801da177e4SLinus Torvalds 	switch (pcode) {
21811da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
21821da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
21831da177e4SLinus Torvalds 		offset += len;
21841da177e4SLinus Torvalds 		break;
21851da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
21861da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
21871da177e4SLinus Torvalds 		offset += len;
21881da177e4SLinus Torvalds 		break;
21891da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2190760f3b03SDouglas Gilbert 		if (is_disk) {
21911da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
21921da177e4SLinus Torvalds 			offset += len;
2193760f3b03SDouglas Gilbert 		} else
2194760f3b03SDouglas Gilbert 			bad_pcode = true;
21951da177e4SLinus Torvalds 		break;
21961da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2197760f3b03SDouglas Gilbert 		if (is_disk) {
21981da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
21991da177e4SLinus Torvalds 			offset += len;
2200760f3b03SDouglas Gilbert 		} else
2201760f3b03SDouglas Gilbert 			bad_pcode = true;
22021da177e4SLinus Torvalds 		break;
22031da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
22041da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
22051da177e4SLinus Torvalds 		offset += len;
22061da177e4SLinus Torvalds 		break;
2207c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2208c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
220922017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2210c65b1445SDouglas Gilbert 			return check_condition_result;
2211c65b1445SDouglas Gilbert 		}
2212c65b1445SDouglas Gilbert 		len = 0;
2213c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2214c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2215c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2216c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2217c65b1445SDouglas Gilbert 						  target_dev_id);
2218c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2219c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2220c65b1445SDouglas Gilbert 		offset += len;
2221c65b1445SDouglas Gilbert 		break;
22221da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
22231da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
22241da177e4SLinus Torvalds 		offset += len;
22251da177e4SLinus Torvalds 		break;
22261da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2227c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
22281da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
22291da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2230760f3b03SDouglas Gilbert 			if (is_disk) {
2231760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2232760f3b03SDouglas Gilbert 						      target);
2233760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2234760f3b03SDouglas Gilbert 						       target);
2235760f3b03SDouglas Gilbert 			}
22361da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2237c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2238c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2239c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2240c65b1445SDouglas Gilbert 						  target, target_dev_id);
2241c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2242c65b1445SDouglas Gilbert 			}
22431da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2244760f3b03SDouglas Gilbert 			offset += len;
2245c65b1445SDouglas Gilbert 		} else {
224622017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2247c65b1445SDouglas Gilbert 			return check_condition_result;
2248c65b1445SDouglas Gilbert 		}
22491da177e4SLinus Torvalds 		break;
22501da177e4SLinus Torvalds 	default:
2251760f3b03SDouglas Gilbert 		bad_pcode = true;
2252760f3b03SDouglas Gilbert 		break;
2253760f3b03SDouglas Gilbert 	}
2254760f3b03SDouglas Gilbert 	if (bad_pcode) {
225522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
22561da177e4SLinus Torvalds 		return check_condition_result;
22571da177e4SLinus Torvalds 	}
22581da177e4SLinus Torvalds 	if (msense_6)
22591da177e4SLinus Torvalds 		arr[0] = offset - 1;
2260773642d9SDouglas Gilbert 	else
2261773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
22621da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
22631da177e4SLinus Torvalds }
22641da177e4SLinus Torvalds 
2265c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2266c65b1445SDouglas Gilbert 
2267fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2268fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2269c65b1445SDouglas Gilbert {
2270c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2271c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2272c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
227301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2274c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2275c65b1445SDouglas Gilbert 
2276c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2277c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2278c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2279773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2280c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
228122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2282c65b1445SDouglas Gilbert 		return check_condition_result;
2283c65b1445SDouglas Gilbert 	}
2284c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2285c65b1445SDouglas Gilbert 	if (-1 == res)
2286773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2287773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2288cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2289cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2290cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2291773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2292773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
229323183910SDouglas Gilbert 	if (md_len > 2) {
229422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2295c65b1445SDouglas Gilbert 		return check_condition_result;
2296c65b1445SDouglas Gilbert 	}
2297c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2298c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2299c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2300c65b1445SDouglas Gilbert 	if (ps) {
230122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2302c65b1445SDouglas Gilbert 		return check_condition_result;
2303c65b1445SDouglas Gilbert 	}
2304c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2305773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2306c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2307c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2308cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2309c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2310c65b1445SDouglas Gilbert 		return check_condition_result;
2311c65b1445SDouglas Gilbert 	}
2312c65b1445SDouglas Gilbert 	switch (mpage) {
2313cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2314cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2315cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2316cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2317cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2318cbf67842SDouglas Gilbert 		}
2319cbf67842SDouglas Gilbert 		break;
2320c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2321c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2322c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2323c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
2324773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2325cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2326c65b1445SDouglas Gilbert 		}
2327c65b1445SDouglas Gilbert 		break;
2328c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2329c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2330c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2331c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2332cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2333c65b1445SDouglas Gilbert 		}
2334c65b1445SDouglas Gilbert 		break;
2335c65b1445SDouglas Gilbert 	default:
2336c65b1445SDouglas Gilbert 		break;
2337c65b1445SDouglas Gilbert 	}
233822017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2339c65b1445SDouglas Gilbert 	return check_condition_result;
2340cbf67842SDouglas Gilbert set_mode_changed_ua:
2341cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2342cbf67842SDouglas Gilbert 	return 0;
2343c65b1445SDouglas Gilbert }
2344c65b1445SDouglas Gilbert 
2345c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr)
2346c65b1445SDouglas Gilbert {
2347c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2348c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2349c65b1445SDouglas Gilbert 		};
2350c65b1445SDouglas Gilbert 
2351c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2352c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2353c65b1445SDouglas Gilbert }
2354c65b1445SDouglas Gilbert 
2355c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr)
2356c65b1445SDouglas Gilbert {
2357c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2358c65b1445SDouglas Gilbert 		};
2359c65b1445SDouglas Gilbert 
2360c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2361c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2362c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2363c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2364c65b1445SDouglas Gilbert 	}
2365c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2366c65b1445SDouglas Gilbert }
2367c65b1445SDouglas Gilbert 
2368c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2369c65b1445SDouglas Gilbert 
2370c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2371c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2372c65b1445SDouglas Gilbert {
2373ab17241cSBart Van Assche 	int ppc, sp, pcode, subpcode, alloc_len, len, n;
2374c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
237501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2376c65b1445SDouglas Gilbert 
2377c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2378c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2379c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2380c65b1445SDouglas Gilbert 	if (ppc || sp) {
238122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2382c65b1445SDouglas Gilbert 		return check_condition_result;
2383c65b1445SDouglas Gilbert 	}
2384c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
238523183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2386773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2387c65b1445SDouglas Gilbert 	arr[0] = pcode;
238823183910SDouglas Gilbert 	if (0 == subpcode) {
2389c65b1445SDouglas Gilbert 		switch (pcode) {
2390c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2391c65b1445SDouglas Gilbert 			n = 4;
2392c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2393c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2394c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2395c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2396c65b1445SDouglas Gilbert 			break;
2397c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2398c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2399c65b1445SDouglas Gilbert 			break;
2400c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2401c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2402c65b1445SDouglas Gilbert 			break;
2403c65b1445SDouglas Gilbert 		default:
240422017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2405c65b1445SDouglas Gilbert 			return check_condition_result;
2406c65b1445SDouglas Gilbert 		}
240723183910SDouglas Gilbert 	} else if (0xff == subpcode) {
240823183910SDouglas Gilbert 		arr[0] |= 0x40;
240923183910SDouglas Gilbert 		arr[1] = subpcode;
241023183910SDouglas Gilbert 		switch (pcode) {
241123183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
241223183910SDouglas Gilbert 			n = 4;
241323183910SDouglas Gilbert 			arr[n++] = 0x0;
241423183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
241523183910SDouglas Gilbert 			arr[n++] = 0x0;
241623183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
241723183910SDouglas Gilbert 			arr[n++] = 0xd;
241823183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
241923183910SDouglas Gilbert 			arr[n++] = 0x2f;
242023183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
242123183910SDouglas Gilbert 			arr[3] = n - 4;
242223183910SDouglas Gilbert 			break;
242323183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
242423183910SDouglas Gilbert 			n = 4;
242523183910SDouglas Gilbert 			arr[n++] = 0xd;
242623183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
242723183910SDouglas Gilbert 			arr[3] = n - 4;
242823183910SDouglas Gilbert 			break;
242923183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
243023183910SDouglas Gilbert 			n = 4;
243123183910SDouglas Gilbert 			arr[n++] = 0x2f;
243223183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
243323183910SDouglas Gilbert 			arr[3] = n - 4;
243423183910SDouglas Gilbert 			break;
243523183910SDouglas Gilbert 		default:
243622017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
243723183910SDouglas Gilbert 			return check_condition_result;
243823183910SDouglas Gilbert 		}
243923183910SDouglas Gilbert 	} else {
244022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
244123183910SDouglas Gilbert 		return check_condition_result;
244223183910SDouglas Gilbert 	}
2443773642d9SDouglas Gilbert 	len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
2444c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
2445c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
2446c65b1445SDouglas Gilbert }
2447c65b1445SDouglas Gilbert 
2448cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp,
244919789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
24501da177e4SLinus Torvalds {
2451c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
245222017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
24531da177e4SLinus Torvalds 		return check_condition_result;
24541da177e4SLinus Torvalds 	}
2455c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2456c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
245722017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2458cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2459c65b1445SDouglas Gilbert 		return check_condition_result;
2460c65b1445SDouglas Gilbert 	}
246119789100SFUJITA Tomonori 	return 0;
246219789100SFUJITA Tomonori }
246319789100SFUJITA Tomonori 
2464a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
24650a7e69c7SDouglas Gilbert static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
24660a7e69c7SDouglas Gilbert 			    u32 num, bool do_write)
246719789100SFUJITA Tomonori {
246819789100SFUJITA Tomonori 	int ret;
2469c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2470a4517511SAkinobu Mita 	struct scsi_data_buffer *sdb;
2471a4517511SAkinobu Mita 	enum dma_data_direction dir;
247219789100SFUJITA Tomonori 
2473c2248fc9SDouglas Gilbert 	if (do_write) {
2474a4517511SAkinobu Mita 		sdb = scsi_out(scmd);
2475a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
2476a4517511SAkinobu Mita 	} else {
2477a4517511SAkinobu Mita 		sdb = scsi_in(scmd);
2478a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2479a4517511SAkinobu Mita 	}
2480a4517511SAkinobu Mita 
2481a4517511SAkinobu Mita 	if (!sdb->length)
2482a4517511SAkinobu Mita 		return 0;
2483a4517511SAkinobu Mita 	if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2484a4517511SAkinobu Mita 		return -1;
248519789100SFUJITA Tomonori 
248619789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
248719789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
248819789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
248919789100SFUJITA Tomonori 
2490386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2491773642d9SDouglas Gilbert 		   fake_storep + (block * sdebug_sector_size),
24920a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
2493773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2494a4517511SAkinobu Mita 		return ret;
2495a4517511SAkinobu Mita 
2496a4517511SAkinobu Mita 	if (rest) {
2497386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2498773642d9SDouglas Gilbert 			    fake_storep, rest * sdebug_sector_size,
24990a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
25000a7e69c7SDouglas Gilbert 			    do_write);
2501a4517511SAkinobu Mita 	}
250219789100SFUJITA Tomonori 
250319789100SFUJITA Tomonori 	return ret;
250419789100SFUJITA Tomonori }
250519789100SFUJITA Tomonori 
250638d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of
250738d5c833SDouglas Gilbert  * arr into fake_store(lba,num) and return true. If comparison fails then
250838d5c833SDouglas Gilbert  * return false. */
2509fd32119bSDouglas Gilbert static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
251038d5c833SDouglas Gilbert {
251138d5c833SDouglas Gilbert 	bool res;
251238d5c833SDouglas Gilbert 	u64 block, rest = 0;
251338d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2514773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
251538d5c833SDouglas Gilbert 
251638d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
251738d5c833SDouglas Gilbert 	if (block + num > store_blks)
251838d5c833SDouglas Gilbert 		rest = block + num - store_blks;
251938d5c833SDouglas Gilbert 
252038d5c833SDouglas Gilbert 	res = !memcmp(fake_storep + (block * lb_size), arr,
252138d5c833SDouglas Gilbert 		      (num - rest) * lb_size);
252238d5c833SDouglas Gilbert 	if (!res)
252338d5c833SDouglas Gilbert 		return res;
252438d5c833SDouglas Gilbert 	if (rest)
252538d5c833SDouglas Gilbert 		res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
252638d5c833SDouglas Gilbert 			     rest * lb_size);
252738d5c833SDouglas Gilbert 	if (!res)
252838d5c833SDouglas Gilbert 		return res;
252938d5c833SDouglas Gilbert 	arr += num * lb_size;
253038d5c833SDouglas Gilbert 	memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
253138d5c833SDouglas Gilbert 	if (rest)
253238d5c833SDouglas Gilbert 		memcpy(fake_storep, arr + ((num - rest) * lb_size),
253338d5c833SDouglas Gilbert 		       rest * lb_size);
253438d5c833SDouglas Gilbert 	return res;
253538d5c833SDouglas Gilbert }
253638d5c833SDouglas Gilbert 
253751d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2538beb40ea4SAkinobu Mita {
253951d648afSAkinobu Mita 	__be16 csum;
2540beb40ea4SAkinobu Mita 
2541773642d9SDouglas Gilbert 	if (sdebug_guard)
254251d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
254351d648afSAkinobu Mita 	else
2544beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
254551d648afSAkinobu Mita 
2546beb40ea4SAkinobu Mita 	return csum;
2547beb40ea4SAkinobu Mita }
2548beb40ea4SAkinobu Mita 
25496ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
2550beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
2551beb40ea4SAkinobu Mita {
2552773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
2553beb40ea4SAkinobu Mita 
2554beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
2555c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
2556beb40ea4SAkinobu Mita 			(unsigned long)sector,
2557beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
2558beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
2559beb40ea4SAkinobu Mita 		return 0x01;
2560beb40ea4SAkinobu Mita 	}
25618475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
2562beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
2563c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2564c1287970STomas Winkler 			(unsigned long)sector);
2565beb40ea4SAkinobu Mita 		return 0x03;
2566beb40ea4SAkinobu Mita 	}
25678475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2568beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
2569c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2570c1287970STomas Winkler 			(unsigned long)sector);
2571beb40ea4SAkinobu Mita 		return 0x03;
2572beb40ea4SAkinobu Mita 	}
2573beb40ea4SAkinobu Mita 	return 0;
2574beb40ea4SAkinobu Mita }
2575beb40ea4SAkinobu Mita 
2576bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
257765f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
2578c6a44287SMartin K. Petersen {
2579be4e11beSAkinobu Mita 	size_t resid;
2580c6a44287SMartin K. Petersen 	void *paddr;
258114faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
2582be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
2583c6a44287SMartin K. Petersen 
2584e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
2585e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
2586c6a44287SMartin K. Petersen 
2587be4e11beSAkinobu Mita 	sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2588be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2589be4e11beSAkinobu Mita 			(read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2590be4e11beSAkinobu Mita 
2591be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
2592be4e11beSAkinobu Mita 		size_t len = min(miter.length, resid);
259314faa944SAkinobu Mita 		void *start = dif_store(sector);
2594be4e11beSAkinobu Mita 		size_t rest = 0;
259514faa944SAkinobu Mita 
259614faa944SAkinobu Mita 		if (dif_store_end < start + len)
259714faa944SAkinobu Mita 			rest = start + len - dif_store_end;
2598c6a44287SMartin K. Petersen 
2599be4e11beSAkinobu Mita 		paddr = miter.addr;
260014faa944SAkinobu Mita 
260165f72f2aSAkinobu Mita 		if (read)
260265f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
260365f72f2aSAkinobu Mita 		else
260465f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
260565f72f2aSAkinobu Mita 
260665f72f2aSAkinobu Mita 		if (rest) {
260765f72f2aSAkinobu Mita 			if (read)
260814faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
260965f72f2aSAkinobu Mita 			else
261065f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
261165f72f2aSAkinobu Mita 		}
2612c6a44287SMartin K. Petersen 
2613e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
2614c6a44287SMartin K. Petersen 		resid -= len;
2615c6a44287SMartin K. Petersen 	}
2616be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
2617bb8c063cSAkinobu Mita }
2618c6a44287SMartin K. Petersen 
2619bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2620bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
2621bb8c063cSAkinobu Mita {
2622bb8c063cSAkinobu Mita 	unsigned int i;
26236ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
2624bb8c063cSAkinobu Mita 	sector_t sector;
2625bb8c063cSAkinobu Mita 
2626c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
2627bb8c063cSAkinobu Mita 		int ret;
2628bb8c063cSAkinobu Mita 
2629bb8c063cSAkinobu Mita 		sector = start_sec + i;
2630bb8c063cSAkinobu Mita 		sdt = dif_store(sector);
2631bb8c063cSAkinobu Mita 
263251d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
2633bb8c063cSAkinobu Mita 			continue;
2634bb8c063cSAkinobu Mita 
2635bb8c063cSAkinobu Mita 		ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2636bb8c063cSAkinobu Mita 		if (ret) {
2637bb8c063cSAkinobu Mita 			dif_errors++;
2638bb8c063cSAkinobu Mita 			return ret;
2639bb8c063cSAkinobu Mita 		}
2640bb8c063cSAkinobu Mita 	}
2641bb8c063cSAkinobu Mita 
264265f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, true);
2643c6a44287SMartin K. Petersen 	dix_reads++;
2644c6a44287SMartin K. Petersen 
2645c6a44287SMartin K. Petersen 	return 0;
2646c6a44287SMartin K. Petersen }
2647c6a44287SMartin K. Petersen 
2648fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
264919789100SFUJITA Tomonori {
2650c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2651c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
2652c2248fc9SDouglas Gilbert 	u64 lba;
2653c2248fc9SDouglas Gilbert 	u32 num;
2654c2248fc9SDouglas Gilbert 	u32 ei_lba;
265519789100SFUJITA Tomonori 	unsigned long iflags;
265619789100SFUJITA Tomonori 	int ret;
2657c2248fc9SDouglas Gilbert 	bool check_prot;
265819789100SFUJITA Tomonori 
2659c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2660c2248fc9SDouglas Gilbert 	case READ_16:
2661c2248fc9SDouglas Gilbert 		ei_lba = 0;
2662c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2663c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2664c2248fc9SDouglas Gilbert 		check_prot = true;
2665c2248fc9SDouglas Gilbert 		break;
2666c2248fc9SDouglas Gilbert 	case READ_10:
2667c2248fc9SDouglas Gilbert 		ei_lba = 0;
2668c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2669c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2670c2248fc9SDouglas Gilbert 		check_prot = true;
2671c2248fc9SDouglas Gilbert 		break;
2672c2248fc9SDouglas Gilbert 	case READ_6:
2673c2248fc9SDouglas Gilbert 		ei_lba = 0;
2674c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2675c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2676c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2677c2248fc9SDouglas Gilbert 		check_prot = true;
2678c2248fc9SDouglas Gilbert 		break;
2679c2248fc9SDouglas Gilbert 	case READ_12:
2680c2248fc9SDouglas Gilbert 		ei_lba = 0;
2681c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2682c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2683c2248fc9SDouglas Gilbert 		check_prot = true;
2684c2248fc9SDouglas Gilbert 		break;
2685c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
2686c2248fc9SDouglas Gilbert 		ei_lba = 0;
2687c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2688c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2689c2248fc9SDouglas Gilbert 		check_prot = false;
2690c2248fc9SDouglas Gilbert 		break;
2691c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
2692c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2693c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2694c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2695c2248fc9SDouglas Gilbert 		check_prot = false;
2696c2248fc9SDouglas Gilbert 		break;
2697c2248fc9SDouglas Gilbert 	}
2698f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
26998475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2700c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2701c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2702c2248fc9SDouglas Gilbert 			return check_condition_result;
2703c2248fc9SDouglas Gilbert 		}
27048475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
27058475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
2706c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2707c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2708c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2709c2248fc9SDouglas Gilbert 	}
2710f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
2711c4837394SDouglas Gilbert 		sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
2712c2248fc9SDouglas Gilbert 
2713c4837394SDouglas Gilbert 		if (sqcp) {
2714c4837394SDouglas Gilbert 			if (sqcp->inj_short)
2715c2248fc9SDouglas Gilbert 				num /= 2;
2716c2248fc9SDouglas Gilbert 		}
2717c4837394SDouglas Gilbert 	} else
2718c4837394SDouglas Gilbert 		sqcp = NULL;
2719c2248fc9SDouglas Gilbert 
2720c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2721f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
2722c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2723c2248fc9SDouglas Gilbert 		return check_condition_result;
2724c2248fc9SDouglas Gilbert 	}
2725c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2726f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
2727c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2728c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2729c2248fc9SDouglas Gilbert 		return check_condition_result;
2730c2248fc9SDouglas Gilbert 	}
273119789100SFUJITA Tomonori 
2732f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
2733d9da891aSLaurence Oberman 		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
2734d9da891aSLaurence Oberman 		     ((lba + num) > sdebug_medium_error_start))) {
2735c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
2736c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
2737c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
2738c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2739c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
274032f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
274132f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
2742c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
2743c65b1445SDouglas Gilbert 		}
2744c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
27451da177e4SLinus Torvalds 		return check_condition_result;
27461da177e4SLinus Torvalds 	}
2747c6a44287SMartin K. Petersen 
27486c78cc06SAkinobu Mita 	read_lock_irqsave(&atomic_rw, iflags);
27496c78cc06SAkinobu Mita 
2750c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2751f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
2752c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
2753c6a44287SMartin K. Petersen 
2754c6a44287SMartin K. Petersen 		if (prot_ret) {
27556c78cc06SAkinobu Mita 			read_unlock_irqrestore(&atomic_rw, iflags);
2756c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
2757c6a44287SMartin K. Petersen 			return illegal_condition_result;
2758c6a44287SMartin K. Petersen 		}
2759c6a44287SMartin K. Petersen 	}
2760c6a44287SMartin K. Petersen 
27610a7e69c7SDouglas Gilbert 	ret = do_device_access(scp, 0, lba, num, false);
27621da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
2763f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
2764a4517511SAkinobu Mita 		return DID_ERROR << 16;
2765a4517511SAkinobu Mita 
2766c2248fc9SDouglas Gilbert 	scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
2767a4517511SAkinobu Mita 
2768c4837394SDouglas Gilbert 	if (unlikely(sqcp)) {
2769c4837394SDouglas Gilbert 		if (sqcp->inj_recovered) {
2770c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
2771c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
2772c2248fc9SDouglas Gilbert 			return check_condition_result;
2773c4837394SDouglas Gilbert 		} else if (sqcp->inj_transport) {
2774c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND,
2775c2248fc9SDouglas Gilbert 					TRANSPORT_PROBLEM, ACK_NAK_TO);
2776c2248fc9SDouglas Gilbert 			return check_condition_result;
2777c4837394SDouglas Gilbert 		} else if (sqcp->inj_dif) {
2778c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
2779c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2780c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2781c4837394SDouglas Gilbert 		} else if (sqcp->inj_dix) {
2782c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2783c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2784c2248fc9SDouglas Gilbert 		}
2785c2248fc9SDouglas Gilbert 	}
2786a4517511SAkinobu Mita 	return 0;
27871da177e4SLinus Torvalds }
27881da177e4SLinus Torvalds 
278958a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len)
2790c6a44287SMartin K. Petersen {
2791cbf67842SDouglas Gilbert 	int i, j, n;
2792c6a44287SMartin K. Petersen 
2793cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
2794c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
2795cbf67842SDouglas Gilbert 		char b[128];
2796c6a44287SMartin K. Petersen 
2797cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
2798c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
2799c6a44287SMartin K. Petersen 
2800cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
2801cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2802cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
2803cbf67842SDouglas Gilbert 			else
2804cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2805cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
2806cbf67842SDouglas Gilbert 		}
2807cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
2808c6a44287SMartin K. Petersen 	}
2809c6a44287SMartin K. Petersen }
2810c6a44287SMartin K. Petersen 
2811c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
2812395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
2813c6a44287SMartin K. Petersen {
2814be4e11beSAkinobu Mita 	int ret;
28156ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
2816be4e11beSAkinobu Mita 	void *daddr;
281765f72f2aSAkinobu Mita 	sector_t sector = start_sec;
2818c6a44287SMartin K. Petersen 	int ppage_offset;
2819be4e11beSAkinobu Mita 	int dpage_offset;
2820be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
2821be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
2822c6a44287SMartin K. Petersen 
2823c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
2824c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2825c6a44287SMartin K. Petersen 
2826be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2827be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
2828be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2829be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2830be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2831c6a44287SMartin K. Petersen 
2832be4e11beSAkinobu Mita 	/* For each protection page */
2833be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
2834be4e11beSAkinobu Mita 		dpage_offset = 0;
2835be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
2836be4e11beSAkinobu Mita 			ret = 0x01;
2837be4e11beSAkinobu Mita 			goto out;
2838c6a44287SMartin K. Petersen 		}
2839c6a44287SMartin K. Petersen 
2840be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
28416ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
2842be4e11beSAkinobu Mita 			/* If we're at the end of the current
2843be4e11beSAkinobu Mita 			 * data page advance to the next one
2844be4e11beSAkinobu Mita 			 */
2845be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
2846be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
2847be4e11beSAkinobu Mita 					ret = 0x01;
2848be4e11beSAkinobu Mita 					goto out;
2849be4e11beSAkinobu Mita 				}
2850be4e11beSAkinobu Mita 				dpage_offset = 0;
2851be4e11beSAkinobu Mita 			}
2852c6a44287SMartin K. Petersen 
2853be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
2854be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
2855be4e11beSAkinobu Mita 
2856be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
2857beb40ea4SAkinobu Mita 			if (ret) {
2858773642d9SDouglas Gilbert 				dump_sector(daddr, sdebug_sector_size);
2859395cef03SMartin K. Petersen 				goto out;
2860395cef03SMartin K. Petersen 			}
2861395cef03SMartin K. Petersen 
2862c6a44287SMartin K. Petersen 			sector++;
2863395cef03SMartin K. Petersen 			ei_lba++;
2864773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
2865c6a44287SMartin K. Petersen 		}
2866be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
2867be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
2868c6a44287SMartin K. Petersen 	}
2869be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2870c6a44287SMartin K. Petersen 
287165f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
2872c6a44287SMartin K. Petersen 	dix_writes++;
2873c6a44287SMartin K. Petersen 
2874c6a44287SMartin K. Petersen 	return 0;
2875c6a44287SMartin K. Petersen 
2876c6a44287SMartin K. Petersen out:
2877c6a44287SMartin K. Petersen 	dif_errors++;
2878be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
2879be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2880c6a44287SMartin K. Petersen 	return ret;
2881c6a44287SMartin K. Petersen }
2882c6a44287SMartin K. Petersen 
2883b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
2884b90ebc3dSAkinobu Mita {
2885773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2886773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2887773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
2888b90ebc3dSAkinobu Mita 	return lba;
2889b90ebc3dSAkinobu Mita }
2890b90ebc3dSAkinobu Mita 
2891b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
2892b90ebc3dSAkinobu Mita {
2893773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
2894a027b5b9SAkinobu Mita 
2895773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2896773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
2897a027b5b9SAkinobu Mita 	return lba;
2898a027b5b9SAkinobu Mita }
2899a027b5b9SAkinobu Mita 
290044d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
290144d92694SMartin K. Petersen {
2902b90ebc3dSAkinobu Mita 	sector_t end;
2903b90ebc3dSAkinobu Mita 	unsigned int mapped;
2904b90ebc3dSAkinobu Mita 	unsigned long index;
2905b90ebc3dSAkinobu Mita 	unsigned long next;
290644d92694SMartin K. Petersen 
2907b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
2908b90ebc3dSAkinobu Mita 	mapped = test_bit(index, map_storep);
290944d92694SMartin K. Petersen 
291044d92694SMartin K. Petersen 	if (mapped)
2911b90ebc3dSAkinobu Mita 		next = find_next_zero_bit(map_storep, map_size, index);
291244d92694SMartin K. Petersen 	else
2913b90ebc3dSAkinobu Mita 		next = find_next_bit(map_storep, map_size, index);
291444d92694SMartin K. Petersen 
2915b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
291644d92694SMartin K. Petersen 	*num = end - lba;
291744d92694SMartin K. Petersen 	return mapped;
291844d92694SMartin K. Petersen }
291944d92694SMartin K. Petersen 
292044d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
292144d92694SMartin K. Petersen {
292244d92694SMartin K. Petersen 	sector_t end = lba + len;
292344d92694SMartin K. Petersen 
292444d92694SMartin K. Petersen 	while (lba < end) {
2925b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
292644d92694SMartin K. Petersen 
2927b90ebc3dSAkinobu Mita 		if (index < map_size)
2928b90ebc3dSAkinobu Mita 			set_bit(index, map_storep);
292944d92694SMartin K. Petersen 
2930b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
293144d92694SMartin K. Petersen 	}
293244d92694SMartin K. Petersen }
293344d92694SMartin K. Petersen 
293444d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
293544d92694SMartin K. Petersen {
293644d92694SMartin K. Petersen 	sector_t end = lba + len;
293744d92694SMartin K. Petersen 
293844d92694SMartin K. Petersen 	while (lba < end) {
2939b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
294044d92694SMartin K. Petersen 
2941b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
2942773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
2943b90ebc3dSAkinobu Mita 		    index < map_size) {
2944b90ebc3dSAkinobu Mita 			clear_bit(index, map_storep);
2945760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
2946be1dd78dSEric Sandeen 				memset(fake_storep +
2947760f3b03SDouglas Gilbert 				       lba * sdebug_sector_size,
2948760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
2949773642d9SDouglas Gilbert 				       sdebug_sector_size *
2950773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2951be1dd78dSEric Sandeen 			}
2952e9926b43SAkinobu Mita 			if (dif_storep) {
2953e9926b43SAkinobu Mita 				memset(dif_storep + lba, 0xff,
2954e9926b43SAkinobu Mita 				       sizeof(*dif_storep) *
2955773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2956e9926b43SAkinobu Mita 			}
2957b90ebc3dSAkinobu Mita 		}
2958b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
295944d92694SMartin K. Petersen 	}
296044d92694SMartin K. Petersen }
296144d92694SMartin K. Petersen 
2962fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
29631da177e4SLinus Torvalds {
2964c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2965c2248fc9SDouglas Gilbert 	u64 lba;
2966c2248fc9SDouglas Gilbert 	u32 num;
2967c2248fc9SDouglas Gilbert 	u32 ei_lba;
29681da177e4SLinus Torvalds 	unsigned long iflags;
296919789100SFUJITA Tomonori 	int ret;
2970c2248fc9SDouglas Gilbert 	bool check_prot;
29711da177e4SLinus Torvalds 
2972c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2973c2248fc9SDouglas Gilbert 	case WRITE_16:
2974c2248fc9SDouglas Gilbert 		ei_lba = 0;
2975c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2976c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2977c2248fc9SDouglas Gilbert 		check_prot = true;
2978c2248fc9SDouglas Gilbert 		break;
2979c2248fc9SDouglas Gilbert 	case WRITE_10:
2980c2248fc9SDouglas Gilbert 		ei_lba = 0;
2981c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2982c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2983c2248fc9SDouglas Gilbert 		check_prot = true;
2984c2248fc9SDouglas Gilbert 		break;
2985c2248fc9SDouglas Gilbert 	case WRITE_6:
2986c2248fc9SDouglas Gilbert 		ei_lba = 0;
2987c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2988c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2989c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2990c2248fc9SDouglas Gilbert 		check_prot = true;
2991c2248fc9SDouglas Gilbert 		break;
2992c2248fc9SDouglas Gilbert 	case WRITE_12:
2993c2248fc9SDouglas Gilbert 		ei_lba = 0;
2994c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2995c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2996c2248fc9SDouglas Gilbert 		check_prot = true;
2997c2248fc9SDouglas Gilbert 		break;
2998c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
2999c2248fc9SDouglas Gilbert 		ei_lba = 0;
3000c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3001c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3002c2248fc9SDouglas Gilbert 		check_prot = false;
3003c2248fc9SDouglas Gilbert 		break;
3004c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
3005c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3006c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3007c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3008c2248fc9SDouglas Gilbert 		check_prot = false;
3009c2248fc9SDouglas Gilbert 		break;
3010c2248fc9SDouglas Gilbert 	}
3011f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
30128475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3013c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3014c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3015c2248fc9SDouglas Gilbert 			return check_condition_result;
3016c2248fc9SDouglas Gilbert 		}
30178475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
30188475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3019c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3020c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3021c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3022c2248fc9SDouglas Gilbert 	}
3023c2248fc9SDouglas Gilbert 
3024c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
3025f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
3026c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3027c2248fc9SDouglas Gilbert 		return check_condition_result;
3028c2248fc9SDouglas Gilbert 	}
3029c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
3030f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
3031c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
3032c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3033c2248fc9SDouglas Gilbert 		return check_condition_result;
3034c2248fc9SDouglas Gilbert 	}
30351da177e4SLinus Torvalds 
30366c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
30376c78cc06SAkinobu Mita 
3038c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3039f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3040c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
3041c6a44287SMartin K. Petersen 
3042c6a44287SMartin K. Petersen 		if (prot_ret) {
30436c78cc06SAkinobu Mita 			write_unlock_irqrestore(&atomic_rw, iflags);
3044c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
3045c6a44287SMartin K. Petersen 			return illegal_condition_result;
3046c6a44287SMartin K. Petersen 		}
3047c6a44287SMartin K. Petersen 	}
3048c6a44287SMartin K. Petersen 
30490a7e69c7SDouglas Gilbert 	ret = do_device_access(scp, 0, lba, num, true);
3050f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
305144d92694SMartin K. Petersen 		map_region(lba, num);
30521da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
3053f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3054773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3055c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3056c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3057c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3058cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3059773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
306044d92694SMartin K. Petersen 
3061f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
3062c4837394SDouglas Gilbert 		struct sdebug_queued_cmd *sqcp =
3063c4837394SDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
3064c2248fc9SDouglas Gilbert 
3065c4837394SDouglas Gilbert 		if (sqcp) {
3066c4837394SDouglas Gilbert 			if (sqcp->inj_recovered) {
3067c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR,
3068c2248fc9SDouglas Gilbert 						THRESHOLD_EXCEEDED, 0);
3069c2248fc9SDouglas Gilbert 				return check_condition_result;
3070c4837394SDouglas Gilbert 			} else if (sqcp->inj_dif) {
3071c2248fc9SDouglas Gilbert 				/* Logical block guard check failed */
3072c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3073c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3074c4837394SDouglas Gilbert 			} else if (sqcp->inj_dix) {
3075c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3076c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3077c2248fc9SDouglas Gilbert 			}
3078c2248fc9SDouglas Gilbert 		}
3079c4837394SDouglas Gilbert 	}
30801da177e4SLinus Torvalds 	return 0;
30811da177e4SLinus Torvalds }
30821da177e4SLinus Torvalds 
3083481b5e5cSDouglas Gilbert /*
3084481b5e5cSDouglas Gilbert  * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3085481b5e5cSDouglas Gilbert  * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3086481b5e5cSDouglas Gilbert  */
3087481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp,
3088481b5e5cSDouglas Gilbert 			   struct sdebug_dev_info *devip)
3089481b5e5cSDouglas Gilbert {
3090481b5e5cSDouglas Gilbert 	u8 *cmd = scp->cmnd;
3091481b5e5cSDouglas Gilbert 	u8 *lrdp = NULL;
3092481b5e5cSDouglas Gilbert 	u8 *up;
3093481b5e5cSDouglas Gilbert 	u8 wrprotect;
3094481b5e5cSDouglas Gilbert 	u16 lbdof, num_lrd, k;
3095481b5e5cSDouglas Gilbert 	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3096481b5e5cSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
3097481b5e5cSDouglas Gilbert 	u32 ei_lba;
3098481b5e5cSDouglas Gilbert 	u64 lba;
3099481b5e5cSDouglas Gilbert 	unsigned long iflags;
3100481b5e5cSDouglas Gilbert 	int ret, res;
3101481b5e5cSDouglas Gilbert 	bool is_16;
3102481b5e5cSDouglas Gilbert 	static const u32 lrd_size = 32; /* + parameter list header size */
3103481b5e5cSDouglas Gilbert 
3104481b5e5cSDouglas Gilbert 	if (cmd[0] == VARIABLE_LENGTH_CMD) {
3105481b5e5cSDouglas Gilbert 		is_16 = false;
3106481b5e5cSDouglas Gilbert 		wrprotect = (cmd[10] >> 5) & 0x7;
3107481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 12);
3108481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 16);
3109481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 28);
3110481b5e5cSDouglas Gilbert 	} else {        /* that leaves WRITE SCATTERED(16) */
3111481b5e5cSDouglas Gilbert 		is_16 = true;
3112481b5e5cSDouglas Gilbert 		wrprotect = (cmd[2] >> 5) & 0x7;
3113481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 4);
3114481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 8);
3115481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 10);
3116481b5e5cSDouglas Gilbert 		if (unlikely(have_dif_prot)) {
3117481b5e5cSDouglas Gilbert 			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3118481b5e5cSDouglas Gilbert 			    wrprotect) {
3119481b5e5cSDouglas Gilbert 				mk_sense_invalid_opcode(scp);
3120481b5e5cSDouglas Gilbert 				return illegal_condition_result;
3121481b5e5cSDouglas Gilbert 			}
3122481b5e5cSDouglas Gilbert 			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3123481b5e5cSDouglas Gilbert 			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3124481b5e5cSDouglas Gilbert 			     wrprotect == 0)
3125481b5e5cSDouglas Gilbert 				sdev_printk(KERN_ERR, scp->device,
3126481b5e5cSDouglas Gilbert 					    "Unprotected WR to DIF device\n");
3127481b5e5cSDouglas Gilbert 		}
3128481b5e5cSDouglas Gilbert 	}
3129481b5e5cSDouglas Gilbert 	if ((num_lrd == 0) || (bt_len == 0))
3130481b5e5cSDouglas Gilbert 		return 0;       /* T10 says these do-nothings are not errors */
3131481b5e5cSDouglas Gilbert 	if (lbdof == 0) {
3132481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3133481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3134481b5e5cSDouglas Gilbert 				"%s: %s: LB Data Offset field bad\n",
3135481b5e5cSDouglas Gilbert 				my_name, __func__);
3136481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3137481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3138481b5e5cSDouglas Gilbert 	}
3139481b5e5cSDouglas Gilbert 	lbdof_blen = lbdof * lb_size;
3140481b5e5cSDouglas Gilbert 	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3141481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3142481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3143481b5e5cSDouglas Gilbert 				"%s: %s: LBA range descriptors don't fit\n",
3144481b5e5cSDouglas Gilbert 				my_name, __func__);
3145481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3146481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3147481b5e5cSDouglas Gilbert 	}
3148481b5e5cSDouglas Gilbert 	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3149481b5e5cSDouglas Gilbert 	if (lrdp == NULL)
3150481b5e5cSDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3151481b5e5cSDouglas Gilbert 	if (sdebug_verbose)
3152481b5e5cSDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3153481b5e5cSDouglas Gilbert 			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3154481b5e5cSDouglas Gilbert 			my_name, __func__, lbdof_blen);
3155481b5e5cSDouglas Gilbert 	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3156481b5e5cSDouglas Gilbert 	if (res == -1) {
3157481b5e5cSDouglas Gilbert 		ret = DID_ERROR << 16;
3158481b5e5cSDouglas Gilbert 		goto err_out;
3159481b5e5cSDouglas Gilbert 	}
3160481b5e5cSDouglas Gilbert 
3161481b5e5cSDouglas Gilbert 	write_lock_irqsave(&atomic_rw, iflags);
3162481b5e5cSDouglas Gilbert 	sg_off = lbdof_blen;
3163481b5e5cSDouglas Gilbert 	/* Spec says Buffer xfer Length field in number of LBs in dout */
3164481b5e5cSDouglas Gilbert 	cum_lb = 0;
3165481b5e5cSDouglas Gilbert 	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3166481b5e5cSDouglas Gilbert 		lba = get_unaligned_be64(up + 0);
3167481b5e5cSDouglas Gilbert 		num = get_unaligned_be32(up + 8);
3168481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3169481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3170481b5e5cSDouglas Gilbert 				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
3171481b5e5cSDouglas Gilbert 				my_name, __func__, k, lba, num, sg_off);
3172481b5e5cSDouglas Gilbert 		if (num == 0)
3173481b5e5cSDouglas Gilbert 			continue;
3174481b5e5cSDouglas Gilbert 		ret = check_device_access_params(scp, lba, num);
3175481b5e5cSDouglas Gilbert 		if (ret)
3176481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3177481b5e5cSDouglas Gilbert 		num_by = num * lb_size;
3178481b5e5cSDouglas Gilbert 		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3179481b5e5cSDouglas Gilbert 
3180481b5e5cSDouglas Gilbert 		if ((cum_lb + num) > bt_len) {
3181481b5e5cSDouglas Gilbert 			if (sdebug_verbose)
3182481b5e5cSDouglas Gilbert 				sdev_printk(KERN_INFO, scp->device,
3183481b5e5cSDouglas Gilbert 				    "%s: %s: sum of blocks > data provided\n",
3184481b5e5cSDouglas Gilbert 				    my_name, __func__);
3185481b5e5cSDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3186481b5e5cSDouglas Gilbert 					0);
3187481b5e5cSDouglas Gilbert 			ret = illegal_condition_result;
3188481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3189481b5e5cSDouglas Gilbert 		}
3190481b5e5cSDouglas Gilbert 
3191481b5e5cSDouglas Gilbert 		/* DIX + T10 DIF */
3192481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3193481b5e5cSDouglas Gilbert 			int prot_ret = prot_verify_write(scp, lba, num,
3194481b5e5cSDouglas Gilbert 							 ei_lba);
3195481b5e5cSDouglas Gilbert 
3196481b5e5cSDouglas Gilbert 			if (prot_ret) {
3197481b5e5cSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3198481b5e5cSDouglas Gilbert 						prot_ret);
3199481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3200481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3201481b5e5cSDouglas Gilbert 			}
3202481b5e5cSDouglas Gilbert 		}
3203481b5e5cSDouglas Gilbert 
3204481b5e5cSDouglas Gilbert 		ret = do_device_access(scp, sg_off, lba, num, true);
3205481b5e5cSDouglas Gilbert 		if (unlikely(scsi_debug_lbp()))
3206481b5e5cSDouglas Gilbert 			map_region(lba, num);
3207481b5e5cSDouglas Gilbert 		if (unlikely(-1 == ret)) {
3208481b5e5cSDouglas Gilbert 			ret = DID_ERROR << 16;
3209481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3210481b5e5cSDouglas Gilbert 		} else if (unlikely(sdebug_verbose && (ret < num_by)))
3211481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3212481b5e5cSDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3213481b5e5cSDouglas Gilbert 			    my_name, num_by, ret);
3214481b5e5cSDouglas Gilbert 
3215481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_any_injecting_opt)) {
3216481b5e5cSDouglas Gilbert 			struct sdebug_queued_cmd *sqcp =
3217481b5e5cSDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
3218481b5e5cSDouglas Gilbert 
3219481b5e5cSDouglas Gilbert 			if (sqcp) {
3220481b5e5cSDouglas Gilbert 				if (sqcp->inj_recovered) {
3221481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, RECOVERED_ERROR,
3222481b5e5cSDouglas Gilbert 							THRESHOLD_EXCEEDED, 0);
3223481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3224481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3225481b5e5cSDouglas Gilbert 				} else if (sqcp->inj_dif) {
3226481b5e5cSDouglas Gilbert 					/* Logical block guard check failed */
3227481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, ABORTED_COMMAND,
3228481b5e5cSDouglas Gilbert 							0x10, 1);
3229481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3230481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3231481b5e5cSDouglas Gilbert 				} else if (sqcp->inj_dix) {
3232481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, ILLEGAL_REQUEST,
3233481b5e5cSDouglas Gilbert 							0x10, 1);
3234481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3235481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3236481b5e5cSDouglas Gilbert 				}
3237481b5e5cSDouglas Gilbert 			}
3238481b5e5cSDouglas Gilbert 		}
3239481b5e5cSDouglas Gilbert 		sg_off += num_by;
3240481b5e5cSDouglas Gilbert 		cum_lb += num;
3241481b5e5cSDouglas Gilbert 	}
3242481b5e5cSDouglas Gilbert 	ret = 0;
3243481b5e5cSDouglas Gilbert err_out_unlock:
3244481b5e5cSDouglas Gilbert 	write_unlock_irqrestore(&atomic_rw, iflags);
3245481b5e5cSDouglas Gilbert err_out:
3246481b5e5cSDouglas Gilbert 	kfree(lrdp);
3247481b5e5cSDouglas Gilbert 	return ret;
3248481b5e5cSDouglas Gilbert }
3249481b5e5cSDouglas Gilbert 
3250fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3251fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
325244d92694SMartin K. Petersen {
325344d92694SMartin K. Petersen 	unsigned long iflags;
325444d92694SMartin K. Petersen 	unsigned long long i;
325544d92694SMartin K. Petersen 	int ret;
3256773642d9SDouglas Gilbert 	u64 lba_off;
325744d92694SMartin K. Petersen 
3258c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num);
325944d92694SMartin K. Petersen 	if (ret)
326044d92694SMartin K. Petersen 		return ret;
326144d92694SMartin K. Petersen 
326244d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
326344d92694SMartin K. Petersen 
32649ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
326544d92694SMartin K. Petersen 		unmap_region(lba, num);
326644d92694SMartin K. Petersen 		goto out;
326744d92694SMartin K. Petersen 	}
326844d92694SMartin K. Petersen 
3269773642d9SDouglas Gilbert 	lba_off = lba * sdebug_sector_size;
3270c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
3271c2248fc9SDouglas Gilbert 	if (ndob) {
3272773642d9SDouglas Gilbert 		memset(fake_storep + lba_off, 0, sdebug_sector_size);
3273c2248fc9SDouglas Gilbert 		ret = 0;
3274c2248fc9SDouglas Gilbert 	} else
3275773642d9SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
3276773642d9SDouglas Gilbert 					  sdebug_sector_size);
327744d92694SMartin K. Petersen 
327844d92694SMartin K. Petersen 	if (-1 == ret) {
327944d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
3280773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3281e33d7c56SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < sdebug_sector_size))
3282c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3283e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
3284cbf67842SDouglas Gilbert 			    my_name, "write same",
3285e33d7c56SDouglas Gilbert 			    sdebug_sector_size, ret);
328644d92694SMartin K. Petersen 
328744d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
328844d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
3289773642d9SDouglas Gilbert 		memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
3290773642d9SDouglas Gilbert 		       fake_storep + lba_off,
3291773642d9SDouglas Gilbert 		       sdebug_sector_size);
329244d92694SMartin K. Petersen 
32939ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
329444d92694SMartin K. Petersen 		map_region(lba, num);
329544d92694SMartin K. Petersen out:
329644d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
329744d92694SMartin K. Petersen 
329844d92694SMartin K. Petersen 	return 0;
329944d92694SMartin K. Petersen }
330044d92694SMartin K. Petersen 
3301fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3302fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3303c2248fc9SDouglas Gilbert {
3304c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3305c2248fc9SDouglas Gilbert 	u32 lba;
3306c2248fc9SDouglas Gilbert 	u16 num;
3307c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3308c2248fc9SDouglas Gilbert 	bool unmap = false;
3309c2248fc9SDouglas Gilbert 
3310c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3311773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3312c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3313c2248fc9SDouglas Gilbert 			return check_condition_result;
3314c2248fc9SDouglas Gilbert 		} else
3315c2248fc9SDouglas Gilbert 			unmap = true;
3316c2248fc9SDouglas Gilbert 	}
3317c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3318c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3319773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3320c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3321c2248fc9SDouglas Gilbert 		return check_condition_result;
3322c2248fc9SDouglas Gilbert 	}
3323c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3324c2248fc9SDouglas Gilbert }
3325c2248fc9SDouglas Gilbert 
3326fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3327fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3328c2248fc9SDouglas Gilbert {
3329c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3330c2248fc9SDouglas Gilbert 	u64 lba;
3331c2248fc9SDouglas Gilbert 	u32 num;
3332c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3333c2248fc9SDouglas Gilbert 	bool unmap = false;
3334c2248fc9SDouglas Gilbert 	bool ndob = false;
3335c2248fc9SDouglas Gilbert 
3336c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3337773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3338c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3339c2248fc9SDouglas Gilbert 			return check_condition_result;
3340c2248fc9SDouglas Gilbert 		} else
3341c2248fc9SDouglas Gilbert 			unmap = true;
3342c2248fc9SDouglas Gilbert 	}
3343c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3344c2248fc9SDouglas Gilbert 		ndob = true;
3345c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3346c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3347773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3348c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3349c2248fc9SDouglas Gilbert 		return check_condition_result;
3350c2248fc9SDouglas Gilbert 	}
3351c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3352c2248fc9SDouglas Gilbert }
3353c2248fc9SDouglas Gilbert 
3354acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3355acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3356acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3357fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3358fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3359acafd0b9SEwan D. Milne {
3360acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3361acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3362acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3363acafd0b9SEwan D. Milne 	u8 mode;
3364acafd0b9SEwan D. Milne 
3365acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3366acafd0b9SEwan D. Milne 	switch (mode) {
3367acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3368acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3369acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3370acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3371acafd0b9SEwan D. Milne 		break;
3372acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3373acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3374acafd0b9SEwan D. Milne 		break;
3375acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3376acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3377acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3378acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3379acafd0b9SEwan D. Milne 				    dev_list)
3380acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3381acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3382acafd0b9SEwan D. Milne 				if (devip != dp)
3383acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3384acafd0b9SEwan D. Milne 						dp->uas_bm);
3385acafd0b9SEwan D. Milne 			}
3386acafd0b9SEwan D. Milne 		break;
3387acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3388acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3389acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3390acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3391acafd0b9SEwan D. Milne 				    dev_list)
3392acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3393acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3394acafd0b9SEwan D. Milne 					dp->uas_bm);
3395acafd0b9SEwan D. Milne 		break;
3396acafd0b9SEwan D. Milne 	default:
3397acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3398acafd0b9SEwan D. Milne 		break;
3399acafd0b9SEwan D. Milne 	}
3400acafd0b9SEwan D. Milne 	return 0;
3401acafd0b9SEwan D. Milne }
3402acafd0b9SEwan D. Milne 
3403fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3404fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
340538d5c833SDouglas Gilbert {
340638d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
340738d5c833SDouglas Gilbert 	u8 *arr;
340838d5c833SDouglas Gilbert 	u8 *fake_storep_hold;
340938d5c833SDouglas Gilbert 	u64 lba;
341038d5c833SDouglas Gilbert 	u32 dnum;
3411773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
341238d5c833SDouglas Gilbert 	u8 num;
341338d5c833SDouglas Gilbert 	unsigned long iflags;
341438d5c833SDouglas Gilbert 	int ret;
3415d467d31fSDouglas Gilbert 	int retval = 0;
341638d5c833SDouglas Gilbert 
3417d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
341838d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
341938d5c833SDouglas Gilbert 	if (0 == num)
342038d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
34218475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
342238d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
342338d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
342438d5c833SDouglas Gilbert 		return check_condition_result;
342538d5c833SDouglas Gilbert 	}
34268475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
34278475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
342838d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
342938d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
343038d5c833SDouglas Gilbert 			    "to DIF device\n");
343138d5c833SDouglas Gilbert 
343238d5c833SDouglas Gilbert 	/* inline check_device_access_params() */
343338d5c833SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
343438d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
343538d5c833SDouglas Gilbert 		return check_condition_result;
343638d5c833SDouglas Gilbert 	}
343738d5c833SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
343838d5c833SDouglas Gilbert 	if (num > sdebug_store_sectors) {
343938d5c833SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
344038d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
344138d5c833SDouglas Gilbert 		return check_condition_result;
344238d5c833SDouglas Gilbert 	}
3443d467d31fSDouglas Gilbert 	dnum = 2 * num;
3444d467d31fSDouglas Gilbert 	arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3445d467d31fSDouglas Gilbert 	if (NULL == arr) {
3446d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3447d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3448d467d31fSDouglas Gilbert 		return check_condition_result;
3449d467d31fSDouglas Gilbert 	}
345038d5c833SDouglas Gilbert 
345138d5c833SDouglas Gilbert 	write_lock_irqsave(&atomic_rw, iflags);
345238d5c833SDouglas Gilbert 
345338d5c833SDouglas Gilbert 	/* trick do_device_access() to fetch both compare and write buffers
345438d5c833SDouglas Gilbert 	 * from data-in into arr. Safe (atomic) since write_lock held. */
345538d5c833SDouglas Gilbert 	fake_storep_hold = fake_storep;
345638d5c833SDouglas Gilbert 	fake_storep = arr;
34570a7e69c7SDouglas Gilbert 	ret = do_device_access(scp, 0, 0, dnum, true);
345838d5c833SDouglas Gilbert 	fake_storep = fake_storep_hold;
345938d5c833SDouglas Gilbert 	if (ret == -1) {
3460d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3461d467d31fSDouglas Gilbert 		goto cleanup;
3462773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
346338d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
346438d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
346538d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
346638d5c833SDouglas Gilbert 	if (!comp_write_worker(lba, num, arr)) {
346738d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3468d467d31fSDouglas Gilbert 		retval = check_condition_result;
3469d467d31fSDouglas Gilbert 		goto cleanup;
347038d5c833SDouglas Gilbert 	}
347138d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
347238d5c833SDouglas Gilbert 		map_region(lba, num);
3473d467d31fSDouglas Gilbert cleanup:
347438d5c833SDouglas Gilbert 	write_unlock_irqrestore(&atomic_rw, iflags);
3475d467d31fSDouglas Gilbert 	kfree(arr);
3476d467d31fSDouglas Gilbert 	return retval;
347738d5c833SDouglas Gilbert }
347838d5c833SDouglas Gilbert 
347944d92694SMartin K. Petersen struct unmap_block_desc {
348044d92694SMartin K. Petersen 	__be64	lba;
348144d92694SMartin K. Petersen 	__be32	blocks;
348244d92694SMartin K. Petersen 	__be32	__reserved;
348344d92694SMartin K. Petersen };
348444d92694SMartin K. Petersen 
3485fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
348644d92694SMartin K. Petersen {
348744d92694SMartin K. Petersen 	unsigned char *buf;
348844d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
348944d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
349044d92694SMartin K. Petersen 	int ret;
34916c78cc06SAkinobu Mita 	unsigned long iflags;
349244d92694SMartin K. Petersen 
349344d92694SMartin K. Petersen 
3494c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3495c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3496c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3497c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
349844d92694SMartin K. Petersen 
349944d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3500773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3501c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
350244d92694SMartin K. Petersen 		return check_condition_result;
3503c2248fc9SDouglas Gilbert 	}
350444d92694SMartin K. Petersen 
3505b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3506c2248fc9SDouglas Gilbert 	if (!buf) {
3507c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3508c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3509c2248fc9SDouglas Gilbert 		return check_condition_result;
3510c2248fc9SDouglas Gilbert 	}
3511c2248fc9SDouglas Gilbert 
3512c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
351344d92694SMartin K. Petersen 
351444d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
351544d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
351644d92694SMartin K. Petersen 
351744d92694SMartin K. Petersen 	desc = (void *)&buf[8];
351844d92694SMartin K. Petersen 
35196c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
35206c78cc06SAkinobu Mita 
352144d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
352244d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
352344d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
352444d92694SMartin K. Petersen 
3525c2248fc9SDouglas Gilbert 		ret = check_device_access_params(scp, lba, num);
352644d92694SMartin K. Petersen 		if (ret)
352744d92694SMartin K. Petersen 			goto out;
352844d92694SMartin K. Petersen 
352944d92694SMartin K. Petersen 		unmap_region(lba, num);
353044d92694SMartin K. Petersen 	}
353144d92694SMartin K. Petersen 
353244d92694SMartin K. Petersen 	ret = 0;
353344d92694SMartin K. Petersen 
353444d92694SMartin K. Petersen out:
35356c78cc06SAkinobu Mita 	write_unlock_irqrestore(&atomic_rw, iflags);
353644d92694SMartin K. Petersen 	kfree(buf);
353744d92694SMartin K. Petersen 
353844d92694SMartin K. Petersen 	return ret;
353944d92694SMartin K. Petersen }
354044d92694SMartin K. Petersen 
354144d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
354244d92694SMartin K. Petersen 
3543fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
3544fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
354544d92694SMartin K. Petersen {
3546c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3547c2248fc9SDouglas Gilbert 	u64 lba;
3548c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
3549c2248fc9SDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
355044d92694SMartin K. Petersen 	int ret;
355144d92694SMartin K. Petersen 
3552c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3553c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
355444d92694SMartin K. Petersen 
355544d92694SMartin K. Petersen 	if (alloc_len < 24)
355644d92694SMartin K. Petersen 		return 0;
355744d92694SMartin K. Petersen 
3558c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, 1);
355944d92694SMartin K. Petersen 	if (ret)
356044d92694SMartin K. Petersen 		return ret;
356144d92694SMartin K. Petersen 
3562c2248fc9SDouglas Gilbert 	if (scsi_debug_lbp())
356344d92694SMartin K. Petersen 		mapped = map_state(lba, &num);
3564c2248fc9SDouglas Gilbert 	else {
3565c2248fc9SDouglas Gilbert 		mapped = 1;
3566c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
3567c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
3568c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
3569c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
3570c2248fc9SDouglas Gilbert 		else
3571c2248fc9SDouglas Gilbert 			num = 0xffffffff;
3572c2248fc9SDouglas Gilbert 	}
357344d92694SMartin K. Petersen 
357444d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
3575c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
3576c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
3577c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
3578c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
357944d92694SMartin K. Petersen 
3580c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
358144d92694SMartin K. Petersen }
358244d92694SMartin K. Petersen 
358380c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp,
358480c49563SDouglas Gilbert 			   struct sdebug_dev_info *devip)
358580c49563SDouglas Gilbert {
358680c49563SDouglas Gilbert 	u64 lba;
358780c49563SDouglas Gilbert 	u32 num_blocks;
358880c49563SDouglas Gilbert 	u8 *cmd = scp->cmnd;
358980c49563SDouglas Gilbert 
359080c49563SDouglas Gilbert 	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
359180c49563SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
359280c49563SDouglas Gilbert 		num_blocks = get_unaligned_be16(cmd + 7);
359380c49563SDouglas Gilbert 	} else {				/* SYNCHRONIZE_CACHE(16) */
359480c49563SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
359580c49563SDouglas Gilbert 		num_blocks = get_unaligned_be32(cmd + 10);
359680c49563SDouglas Gilbert 	}
359780c49563SDouglas Gilbert 	if (lba + num_blocks > sdebug_capacity) {
359880c49563SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
359980c49563SDouglas Gilbert 		return check_condition_result;
360080c49563SDouglas Gilbert 	}
360180c49563SDouglas Gilbert 	return (cmd[1] & 0x2) ? SDEG_RES_IMMED_MASK : 0; /* check IMMED bit */
360280c49563SDouglas Gilbert }
360380c49563SDouglas Gilbert 
3604fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
3605fb0cc8d1SDouglas Gilbert 
36068d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
36078d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
36088d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
36098d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
36108d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
36118d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
36128d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
36138d039e22SDouglas Gilbert  */
36141da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
36151da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
36161da177e4SLinus Torvalds {
361701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
36188d039e22SDouglas Gilbert 	unsigned int alloc_len;
36198d039e22SDouglas Gilbert 	unsigned char select_report;
36208d039e22SDouglas Gilbert 	u64 lun;
36218d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
3622fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
36238d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
36248d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
36258d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
36268d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
3627fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
3628fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
3629fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
36301da177e4SLinus Torvalds 
363119c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
36328d039e22SDouglas Gilbert 
36338d039e22SDouglas Gilbert 	select_report = cmd[2];
36348d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
36358d039e22SDouglas Gilbert 
36368d039e22SDouglas Gilbert 	if (alloc_len < 4) {
36378d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
36388d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
36391da177e4SLinus Torvalds 		return check_condition_result;
36401da177e4SLinus Torvalds 	}
36418d039e22SDouglas Gilbert 
36428d039e22SDouglas Gilbert 	switch (select_report) {
36438d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
3644773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
36458d039e22SDouglas Gilbert 		wlun_cnt = 0;
36468d039e22SDouglas Gilbert 		break;
36478d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
3648c65b1445SDouglas Gilbert 		lun_cnt = 0;
36498d039e22SDouglas Gilbert 		wlun_cnt = 1;
36508d039e22SDouglas Gilbert 		break;
36518d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
36528d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
36538d039e22SDouglas Gilbert 		wlun_cnt = 1;
36548d039e22SDouglas Gilbert 		break;
36558d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
36568d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
36578d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
36588d039e22SDouglas Gilbert 	default:
36598d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
36608d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
36618d039e22SDouglas Gilbert 		return check_condition_result;
36628d039e22SDouglas Gilbert 	}
36638d039e22SDouglas Gilbert 
36648d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
3665c65b1445SDouglas Gilbert 		--lun_cnt;
36668d039e22SDouglas Gilbert 
36678d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
3668fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
3669fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
36708d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
36718d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
36728d039e22SDouglas Gilbert 
3673fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
36748d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
3675fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3676fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
3677fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
3678fb0cc8d1SDouglas Gilbert 		if (k == 0) {
3679fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
3680fb0cc8d1SDouglas Gilbert 			++lun_p;
3681fb0cc8d1SDouglas Gilbert 			j = 1;
3682fb0cc8d1SDouglas Gilbert 		}
3683fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3684fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3685fb0cc8d1SDouglas Gilbert 				break;
3686fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
3687fb0cc8d1SDouglas Gilbert 		}
3688fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
3689fb0cc8d1SDouglas Gilbert 			break;
3690fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
3691fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3692fb0cc8d1SDouglas Gilbert 		if (res)
3693fb0cc8d1SDouglas Gilbert 			return res;
3694fb0cc8d1SDouglas Gilbert 		off_rsp += n;
3695fb0cc8d1SDouglas Gilbert 	}
3696fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
3697fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3698fb0cc8d1SDouglas Gilbert 		++j;
3699fb0cc8d1SDouglas Gilbert 	}
3700fb0cc8d1SDouglas Gilbert 	if (j > 0)
3701fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
37028d039e22SDouglas Gilbert 	return res;
37031da177e4SLinus Torvalds }
37041da177e4SLinus Torvalds 
3705c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3706c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
3707c639d14eSFUJITA Tomonori {
3708be4e11beSAkinobu Mita 	int j;
3709c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
3710c639d14eSFUJITA Tomonori 	unsigned int offset;
3711c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
3712be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3713c639d14eSFUJITA Tomonori 
3714c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
3715b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3716c5af0db9SAkinobu Mita 	if (!buf) {
371722017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
371822017ed2SDouglas Gilbert 				INSUFF_RES_ASCQ);
3719c5af0db9SAkinobu Mita 		return check_condition_result;
3720c5af0db9SAkinobu Mita 	}
3721c639d14eSFUJITA Tomonori 
372221a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
3723c639d14eSFUJITA Tomonori 
3724c639d14eSFUJITA Tomonori 	offset = 0;
3725be4e11beSAkinobu Mita 	sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3726be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_TO_SG);
3727c639d14eSFUJITA Tomonori 
3728be4e11beSAkinobu Mita 	while (sg_miter_next(&miter)) {
3729be4e11beSAkinobu Mita 		kaddr = miter.addr;
3730be4e11beSAkinobu Mita 		for (j = 0; j < miter.length; j++)
3731be4e11beSAkinobu Mita 			*(kaddr + j) ^= *(buf + offset + j);
3732c639d14eSFUJITA Tomonori 
3733be4e11beSAkinobu Mita 		offset += miter.length;
3734c639d14eSFUJITA Tomonori 	}
3735be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3736c639d14eSFUJITA Tomonori 	kfree(buf);
3737c639d14eSFUJITA Tomonori 
3738be4e11beSAkinobu Mita 	return 0;
3739c639d14eSFUJITA Tomonori }
3740c639d14eSFUJITA Tomonori 
3741fd32119bSDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3742fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
3743c2248fc9SDouglas Gilbert {
3744c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3745c2248fc9SDouglas Gilbert 	u64 lba;
3746c2248fc9SDouglas Gilbert 	u32 num;
3747c2248fc9SDouglas Gilbert 	int errsts;
3748c2248fc9SDouglas Gilbert 
3749c2248fc9SDouglas Gilbert 	if (!scsi_bidi_cmnd(scp)) {
3750c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3751c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3752c2248fc9SDouglas Gilbert 		return check_condition_result;
3753c2248fc9SDouglas Gilbert 	}
3754c2248fc9SDouglas Gilbert 	errsts = resp_read_dt0(scp, devip);
3755c2248fc9SDouglas Gilbert 	if (errsts)
3756c2248fc9SDouglas Gilbert 		return errsts;
3757c2248fc9SDouglas Gilbert 	if (!(cmd[1] & 0x4)) {		/* DISABLE_WRITE is not set */
3758c2248fc9SDouglas Gilbert 		errsts = resp_write_dt0(scp, devip);
3759c2248fc9SDouglas Gilbert 		if (errsts)
3760c2248fc9SDouglas Gilbert 			return errsts;
3761c2248fc9SDouglas Gilbert 	}
3762c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3763c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3764c2248fc9SDouglas Gilbert 	return resp_xdwriteread(scp, lba, num, devip);
3765c2248fc9SDouglas Gilbert }
3766c2248fc9SDouglas Gilbert 
3767c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3768c4837394SDouglas Gilbert {
3769c4837394SDouglas Gilbert 	u32 tag = blk_mq_unique_tag(cmnd->request);
3770c4837394SDouglas Gilbert 	u16 hwq = blk_mq_unique_tag_to_hwq(tag);
3771c4837394SDouglas Gilbert 
3772458df78bSBart Van Assche 	pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
3773458df78bSBart Van Assche 	if (WARN_ON_ONCE(hwq >= submit_queues))
3774458df78bSBart Van Assche 		hwq = 0;
3775458df78bSBart Van Assche 	return sdebug_q_arr + hwq;
3776c4837394SDouglas Gilbert }
3777c4837394SDouglas Gilbert 
3778c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
3779fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
37801da177e4SLinus Torvalds {
3781c4837394SDouglas Gilbert 	int qc_idx;
3782cbf67842SDouglas Gilbert 	int retiring = 0;
37831da177e4SLinus Torvalds 	unsigned long iflags;
3784c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3785cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3786cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
3787cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
37881da177e4SLinus Torvalds 
378910bde980SDouglas Gilbert 	sd_dp->defer_t = SDEB_DEFER_NONE;
3790c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
3791c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
3792c4837394SDouglas Gilbert 	if (sdebug_statistics) {
3793cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
3794c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3795c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
3796c4837394SDouglas Gilbert 	}
3797c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3798c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
37991da177e4SLinus Torvalds 		return;
38001da177e4SLinus Torvalds 	}
3801c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
3802c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
3803cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
3804b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
3805c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3806c4837394SDouglas Gilbert 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3807c4837394SDouglas Gilbert 		       sd_dp->sqa_idx, qc_idx);
38081da177e4SLinus Torvalds 		return;
38091da177e4SLinus Torvalds 	}
3810cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
3811f46eb0e9SDouglas Gilbert 	if (likely(devip))
3812cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
3813cbf67842SDouglas Gilbert 	else
3814c1287970STomas Winkler 		pr_err("devip=NULL\n");
3815f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
3816cbf67842SDouglas Gilbert 		retiring = 1;
3817cbf67842SDouglas Gilbert 
3818cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
3819c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3820c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3821c1287970STomas Winkler 		pr_err("Unexpected completion\n");
3822cbf67842SDouglas Gilbert 		return;
38231da177e4SLinus Torvalds 	}
38241da177e4SLinus Torvalds 
3825cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
3826cbf67842SDouglas Gilbert 		int k, retval;
3827cbf67842SDouglas Gilbert 
3828cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
3829c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
3830c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3831c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
3832cbf67842SDouglas Gilbert 			return;
3833cbf67842SDouglas Gilbert 		}
3834c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
3835773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
3836cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3837cbf67842SDouglas Gilbert 		else
3838cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
3839cbf67842SDouglas Gilbert 	}
3840c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3841cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
3842cbf67842SDouglas Gilbert }
3843cbf67842SDouglas Gilbert 
3844cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
3845fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
3846cbf67842SDouglas Gilbert {
3847a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3848a10bc12aSDouglas Gilbert 						  hrt);
3849a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3850cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
3851cbf67842SDouglas Gilbert }
38521da177e4SLinus Torvalds 
3853a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
3854fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
3855a10bc12aSDouglas Gilbert {
3856a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3857a10bc12aSDouglas Gilbert 						  ew.work);
3858a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3859a10bc12aSDouglas Gilbert }
3860a10bc12aSDouglas Gilbert 
386109ba24c1SDouglas Gilbert static bool got_shared_uuid;
3862bf476433SChristoph Hellwig static uuid_t shared_uuid;
386309ba24c1SDouglas Gilbert 
3864fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
3865fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
38665cb2fc06SFUJITA Tomonori {
38675cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
38685cb2fc06SFUJITA Tomonori 
38695cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
38705cb2fc06SFUJITA Tomonori 	if (devip) {
387109ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
3872bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
387309ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
387409ba24c1SDouglas Gilbert 			if (got_shared_uuid)
387509ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
387609ba24c1SDouglas Gilbert 			else {
3877bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
387809ba24c1SDouglas Gilbert 				got_shared_uuid = true;
387909ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
388009ba24c1SDouglas Gilbert 			}
388109ba24c1SDouglas Gilbert 		}
38825cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
38835cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
38845cb2fc06SFUJITA Tomonori 	}
38855cb2fc06SFUJITA Tomonori 	return devip;
38865cb2fc06SFUJITA Tomonori }
38875cb2fc06SFUJITA Tomonori 
3888f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
38891da177e4SLinus Torvalds {
38901da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
38911da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
3892f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
38931da177e4SLinus Torvalds 
3894d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
38951da177e4SLinus Torvalds 	if (!sdbg_host) {
3896c1287970STomas Winkler 		pr_err("Host info NULL\n");
38971da177e4SLinus Torvalds 		return NULL;
38981da177e4SLinus Torvalds 	}
38991da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
39001da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
39011da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
39021da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
39031da177e4SLinus Torvalds 			return devip;
39041da177e4SLinus Torvalds 		else {
39051da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
39061da177e4SLinus Torvalds 				open_devip = devip;
39071da177e4SLinus Torvalds 		}
39081da177e4SLinus Torvalds 	}
39095cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
39105cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
39115cb2fc06SFUJITA Tomonori 		if (!open_devip) {
3912c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
39131da177e4SLinus Torvalds 			return NULL;
39141da177e4SLinus Torvalds 		}
39151da177e4SLinus Torvalds 	}
3916a75869d1SFUJITA Tomonori 
39171da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
39181da177e4SLinus Torvalds 	open_devip->target = sdev->id;
39191da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
39201da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
3921cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
3922cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
3923c2248fc9SDouglas Gilbert 	open_devip->used = true;
39241da177e4SLinus Torvalds 	return open_devip;
39251da177e4SLinus Torvalds }
39261da177e4SLinus Torvalds 
39278dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
39281da177e4SLinus Torvalds {
3929773642d9SDouglas Gilbert 	if (sdebug_verbose)
3930c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
39318dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
393275ad23bcSNick Piggin 	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
39338dea0d02SFUJITA Tomonori 	return 0;
39348dea0d02SFUJITA Tomonori }
39351da177e4SLinus Torvalds 
39368dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
39378dea0d02SFUJITA Tomonori {
3938f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
3939f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
3940a34c4e98SFUJITA Tomonori 
3941773642d9SDouglas Gilbert 	if (sdebug_verbose)
3942c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
39438dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3944b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3945b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3946b01f6f83SDouglas Gilbert 	if (devip == NULL) {
3947f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
3948b01f6f83SDouglas Gilbert 		if (devip == NULL)
39498dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
3950f46eb0e9SDouglas Gilbert 	}
3951c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
39526bb5e6e7SAkinobu Mita 	blk_queue_max_segment_size(sdp->request_queue, -1U);
3953773642d9SDouglas Gilbert 	if (sdebug_no_uld)
395478d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
39559b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
39568dea0d02SFUJITA Tomonori 	return 0;
39578dea0d02SFUJITA Tomonori }
39588dea0d02SFUJITA Tomonori 
39598dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
39608dea0d02SFUJITA Tomonori {
39618dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
39628dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
39638dea0d02SFUJITA Tomonori 
3964773642d9SDouglas Gilbert 	if (sdebug_verbose)
3965c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
39668dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
39678dea0d02SFUJITA Tomonori 	if (devip) {
396825985edcSLucas De Marchi 		/* make this slot available for re-use */
3969c2248fc9SDouglas Gilbert 		devip->used = false;
39708dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
39718dea0d02SFUJITA Tomonori 	}
39728dea0d02SFUJITA Tomonori }
39738dea0d02SFUJITA Tomonori 
397410bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp,
397510bde980SDouglas Gilbert 			   enum sdeb_defer_type defer_t)
3976c4837394SDouglas Gilbert {
3977c4837394SDouglas Gilbert 	if (!sd_dp)
3978c4837394SDouglas Gilbert 		return;
397910bde980SDouglas Gilbert 	if (defer_t == SDEB_DEFER_HRT)
3980c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
398110bde980SDouglas Gilbert 	else if (defer_t == SDEB_DEFER_WQ)
3982c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
3983c4837394SDouglas Gilbert }
3984c4837394SDouglas Gilbert 
3985a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
3986a10bc12aSDouglas Gilbert    returns false */
3987a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
39888dea0d02SFUJITA Tomonori {
39898dea0d02SFUJITA Tomonori 	unsigned long iflags;
3990c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
399110bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
3992c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
39938dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3994cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3995a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
39968dea0d02SFUJITA Tomonori 
3997c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3998c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
3999773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
4000cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
4001cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
4002cbf67842SDouglas Gilbert 			qmax = r_qmax;
4003cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
4004c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
4005c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
4006a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
4007a10bc12aSDouglas Gilbert 					continue;
4008c4837394SDouglas Gilbert 				/* found */
4009db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
4010db525fceSDouglas Gilbert 						cmnd->device->hostdata;
4011db525fceSDouglas Gilbert 				if (devip)
4012db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
4013db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
4014a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
401510bde980SDouglas Gilbert 				if (sd_dp) {
401610bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
401710bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
401810bde980SDouglas Gilbert 				} else
401910bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
4020c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
402110bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
4022c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
4023a10bc12aSDouglas Gilbert 				return true;
40248dea0d02SFUJITA Tomonori 			}
4025cbf67842SDouglas Gilbert 		}
4026c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4027c4837394SDouglas Gilbert 	}
4028a10bc12aSDouglas Gilbert 	return false;
40298dea0d02SFUJITA Tomonori }
40308dea0d02SFUJITA Tomonori 
4031a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
40328dea0d02SFUJITA Tomonori static void stop_all_queued(void)
40338dea0d02SFUJITA Tomonori {
40348dea0d02SFUJITA Tomonori 	unsigned long iflags;
4035c4837394SDouglas Gilbert 	int j, k;
403610bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
4037c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
40388dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
4039cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4040a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
40418dea0d02SFUJITA Tomonori 
4042c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4043c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
4044c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4045c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
4046c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
4047c4837394SDouglas Gilbert 				if (sqcp->a_cmnd == NULL)
4048a10bc12aSDouglas Gilbert 					continue;
4049db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
4050db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
4051db525fceSDouglas Gilbert 				if (devip)
4052db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
4053db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
4054a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
405510bde980SDouglas Gilbert 				if (sd_dp) {
405610bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
405710bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
405810bde980SDouglas Gilbert 				} else
405910bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
4060c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
406110bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
4062c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
4063c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
40648dea0d02SFUJITA Tomonori 			}
40658dea0d02SFUJITA Tomonori 		}
4066c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4067c4837394SDouglas Gilbert 	}
4068cbf67842SDouglas Gilbert }
4069cbf67842SDouglas Gilbert 
4070cbf67842SDouglas Gilbert /* Free queued command memory on heap */
4071cbf67842SDouglas Gilbert static void free_all_queued(void)
4072cbf67842SDouglas Gilbert {
4073c4837394SDouglas Gilbert 	int j, k;
4074c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4075cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4076cbf67842SDouglas Gilbert 
4077c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4078c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4079c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
4080a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
4081a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
4082cbf67842SDouglas Gilbert 		}
40831da177e4SLinus Torvalds 	}
4084c4837394SDouglas Gilbert }
40851da177e4SLinus Torvalds 
40861da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
40871da177e4SLinus Torvalds {
4088a10bc12aSDouglas Gilbert 	bool ok;
4089a10bc12aSDouglas Gilbert 
40901da177e4SLinus Torvalds 	++num_aborts;
4091cbf67842SDouglas Gilbert 	if (SCpnt) {
4092a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
4093a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
4094a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
4095a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
4096a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
4097cbf67842SDouglas Gilbert 	}
40981da177e4SLinus Torvalds 	return SUCCESS;
40991da177e4SLinus Torvalds }
41001da177e4SLinus Torvalds 
41011da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
41021da177e4SLinus Torvalds {
41031da177e4SLinus Torvalds 	++num_dev_resets;
4104cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
4105cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
4106f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
4107f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
4108cbf67842SDouglas Gilbert 
4109773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
4110cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
41111da177e4SLinus Torvalds 		if (devip)
4112cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
41131da177e4SLinus Torvalds 	}
41141da177e4SLinus Torvalds 	return SUCCESS;
41151da177e4SLinus Torvalds }
41161da177e4SLinus Torvalds 
4117cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
4118cbf67842SDouglas Gilbert {
4119cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
4120cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4121cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
4122cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
4123cbf67842SDouglas Gilbert 	int k = 0;
4124cbf67842SDouglas Gilbert 
4125cbf67842SDouglas Gilbert 	++num_target_resets;
4126cbf67842SDouglas Gilbert 	if (!SCpnt)
4127cbf67842SDouglas Gilbert 		goto lie;
4128cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
4129cbf67842SDouglas Gilbert 	if (!sdp)
4130cbf67842SDouglas Gilbert 		goto lie;
4131773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
4132cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4133cbf67842SDouglas Gilbert 	hp = sdp->host;
4134cbf67842SDouglas Gilbert 	if (!hp)
4135cbf67842SDouglas Gilbert 		goto lie;
4136cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
4137cbf67842SDouglas Gilbert 	if (sdbg_host) {
4138cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
4139cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
4140cbf67842SDouglas Gilbert 				    dev_list)
4141cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
4142cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4143cbf67842SDouglas Gilbert 				++k;
4144cbf67842SDouglas Gilbert 			}
4145cbf67842SDouglas Gilbert 	}
4146773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
4147cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4148cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
4149cbf67842SDouglas Gilbert lie:
4150cbf67842SDouglas Gilbert 	return SUCCESS;
4151cbf67842SDouglas Gilbert }
4152cbf67842SDouglas Gilbert 
41531da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
41541da177e4SLinus Torvalds {
41551da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
4156cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
41571da177e4SLinus Torvalds 	struct scsi_device *sdp;
41581da177e4SLinus Torvalds 	struct Scsi_Host *hp;
4159cbf67842SDouglas Gilbert 	int k = 0;
41601da177e4SLinus Torvalds 
41611da177e4SLinus Torvalds 	++num_bus_resets;
4162cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
4163cbf67842SDouglas Gilbert 		goto lie;
4164cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
4165773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
4166cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4167cbf67842SDouglas Gilbert 	hp = sdp->host;
4168cbf67842SDouglas Gilbert 	if (hp) {
4169d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
41701da177e4SLinus Torvalds 		if (sdbg_host) {
4171cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
41721da177e4SLinus Torvalds 					    &sdbg_host->dev_info_list,
4173cbf67842SDouglas Gilbert 					    dev_list) {
4174cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4175cbf67842SDouglas Gilbert 				++k;
41761da177e4SLinus Torvalds 			}
41771da177e4SLinus Torvalds 		}
4178cbf67842SDouglas Gilbert 	}
4179773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
4180cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4181cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
4182cbf67842SDouglas Gilbert lie:
41831da177e4SLinus Torvalds 	return SUCCESS;
41841da177e4SLinus Torvalds }
41851da177e4SLinus Torvalds 
41861da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
41871da177e4SLinus Torvalds {
41881da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
4189cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4190cbf67842SDouglas Gilbert 	int k = 0;
41911da177e4SLinus Torvalds 
41921da177e4SLinus Torvalds 	++num_host_resets;
4193773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
4194cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
41951da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
41961da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
4197cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
4198cbf67842SDouglas Gilbert 				    dev_list) {
4199cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4200cbf67842SDouglas Gilbert 			++k;
4201cbf67842SDouglas Gilbert 		}
42021da177e4SLinus Torvalds 	}
42031da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
42041da177e4SLinus Torvalds 	stop_all_queued();
4205773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
4206cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
4207cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
42081da177e4SLinus Torvalds 	return SUCCESS;
42091da177e4SLinus Torvalds }
42101da177e4SLinus Torvalds 
4211f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
42125f2578e5SFUJITA Tomonori 				      unsigned long store_size)
42131da177e4SLinus Torvalds {
42141da177e4SLinus Torvalds 	struct partition *pp;
42151da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
42161da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
42171da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
42181da177e4SLinus Torvalds 
42191da177e4SLinus Torvalds 	/* assume partition table already zeroed */
4220773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
42211da177e4SLinus Torvalds 		return;
4222773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
4223773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
4224c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
42251da177e4SLinus Torvalds 	}
4226c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
42271da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
4228773642d9SDouglas Gilbert 			   / sdebug_num_parts;
42291da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
42301da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
4231773642d9SDouglas Gilbert 	for (k = 1; k < sdebug_num_parts; ++k)
42321da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
42331da177e4SLinus Torvalds 			    * heads_by_sects;
4234773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
4235773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
42361da177e4SLinus Torvalds 
42371da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
42381da177e4SLinus Torvalds 	ramp[511] = 0xAA;
42391da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
42401da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
42411da177e4SLinus Torvalds 		start_sec = starts[k];
42421da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
42431da177e4SLinus Torvalds 		pp->boot_ind = 0;
42441da177e4SLinus Torvalds 
42451da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
42461da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
42471da177e4SLinus Torvalds 			   / sdebug_sectors_per;
42481da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
42491da177e4SLinus Torvalds 
42501da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
42511da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
42521da177e4SLinus Torvalds 			       / sdebug_sectors_per;
42531da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
42541da177e4SLinus Torvalds 
4255150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
4256150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
42571da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
42581da177e4SLinus Torvalds 	}
42591da177e4SLinus Torvalds }
42601da177e4SLinus Torvalds 
4261c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block)
4262c4837394SDouglas Gilbert {
4263c4837394SDouglas Gilbert 	int j;
4264c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4265c4837394SDouglas Gilbert 
4266c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
4267c4837394SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)block);
4268c4837394SDouglas Gilbert }
4269c4837394SDouglas Gilbert 
4270c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
4271c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
4272c4837394SDouglas Gilbert  */
4273c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
4274c4837394SDouglas Gilbert {
4275c4837394SDouglas Gilbert 	int count, modulo;
4276c4837394SDouglas Gilbert 
4277c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
4278c4837394SDouglas Gilbert 	if (modulo < 2)
4279c4837394SDouglas Gilbert 		return;
4280c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
4281c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
4282c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
4283c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
4284c4837394SDouglas Gilbert }
4285c4837394SDouglas Gilbert 
4286c4837394SDouglas Gilbert static void clear_queue_stats(void)
4287c4837394SDouglas Gilbert {
4288c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
4289c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
4290c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
4291c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
4292c4837394SDouglas Gilbert }
4293c4837394SDouglas Gilbert 
4294c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp,
4295c4837394SDouglas Gilbert 			 struct sdebug_queued_cmd *sqcp)
4296c4837394SDouglas Gilbert {
4297c4837394SDouglas Gilbert 	if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0)
4298c4837394SDouglas Gilbert 		return;
4299c4837394SDouglas Gilbert 	sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
4300c4837394SDouglas Gilbert 	sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
4301c4837394SDouglas Gilbert 	sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
4302c4837394SDouglas Gilbert 	sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
4303c4837394SDouglas Gilbert 	sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
43047ee6d1b4SBart Van Assche 	sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
4305c4837394SDouglas Gilbert }
4306c4837394SDouglas Gilbert 
4307c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
4308c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
4309c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
4310c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
4311c4837394SDouglas Gilbert  */
4312fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
431310bde980SDouglas Gilbert 			 int scsi_result, int delta_jiff, int ndelay)
43141da177e4SLinus Torvalds {
4315cbf67842SDouglas Gilbert 	unsigned long iflags;
4316cd62b7daSDouglas Gilbert 	int k, num_in_q, qdepth, inject;
4317c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4318c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4319299b6c07STomas Winkler 	struct scsi_device *sdp;
4320a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
43211da177e4SLinus Torvalds 
4322b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
4323b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
4324f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
4325f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
43261da177e4SLinus Torvalds 	}
4327299b6c07STomas Winkler 	sdp = cmnd->device;
4328299b6c07STomas Winkler 
4329f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose && scsi_result))
4330cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4331cbf67842SDouglas Gilbert 			    __func__, scsi_result);
4332cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
4333cd62b7daSDouglas Gilbert 		goto respond_in_thread;
43341da177e4SLinus Torvalds 
4335cd62b7daSDouglas Gilbert 	/* schedule the response at a later time if resources permit */
4336c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
4337c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
4338c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
4339c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4340c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
4341c4837394SDouglas Gilbert 	}
4342cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
4343cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
4344cbf67842SDouglas Gilbert 	inject = 0;
4345f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
4346cd62b7daSDouglas Gilbert 		if (scsi_result) {
4347c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4348cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4349cd62b7daSDouglas Gilbert 		} else
4350cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4351c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
4352773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4353f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
4354cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
4355cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
4356773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
4357cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
4358cbf67842SDouglas Gilbert 			inject = 1;
4359cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
43601da177e4SLinus Torvalds 		}
4361cbf67842SDouglas Gilbert 	}
4362cbf67842SDouglas Gilbert 
4363c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
4364f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
4365c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4366cd62b7daSDouglas Gilbert 		if (scsi_result)
4367cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4368773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
4369cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4370773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
4371cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
4372cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
4373773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
4374cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
4375cbf67842SDouglas Gilbert 						    "report: host busy"));
4376cd62b7daSDouglas Gilbert 		if (scsi_result)
4377cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4378cd62b7daSDouglas Gilbert 		else
4379cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
43801da177e4SLinus Torvalds 	}
4381c4837394SDouglas Gilbert 	__set_bit(k, sqp->in_use_bm);
4382cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
4383c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
43841da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
4385c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
4386cbf67842SDouglas Gilbert 	cmnd->result = scsi_result;
4387a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
4388c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4389c4837394SDouglas Gilbert 	if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4390c4837394SDouglas Gilbert 		setup_inject(sqp, sqcp);
439110bde980SDouglas Gilbert 	if (sd_dp == NULL) {
439210bde980SDouglas Gilbert 		sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
439310bde980SDouglas Gilbert 		if (sd_dp == NULL)
439410bde980SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
439510bde980SDouglas Gilbert 	}
439610bde980SDouglas Gilbert 	if (delta_jiff > 0 || ndelay > 0) {
4397b333a819SDouglas Gilbert 		ktime_t kt;
4398cbf67842SDouglas Gilbert 
4399b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
440013f6b610SArnd Bergmann 			kt = ns_to_ktime((u64)delta_jiff * (NSEC_PER_SEC / HZ));
4401b333a819SDouglas Gilbert 		} else
440210bde980SDouglas Gilbert 			kt = ndelay;
440310bde980SDouglas Gilbert 		if (!sd_dp->init_hrt) {
440410bde980SDouglas Gilbert 			sd_dp->init_hrt = true;
4405a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4406a10bc12aSDouglas Gilbert 			hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
4407c4837394SDouglas Gilbert 				     HRTIMER_MODE_REL_PINNED);
4408a10bc12aSDouglas Gilbert 			sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
4409c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4410c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4411cbf67842SDouglas Gilbert 		}
4412c4837394SDouglas Gilbert 		if (sdebug_statistics)
4413c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
441410bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_HRT;
4415c4837394SDouglas Gilbert 		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4416c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
441710bde980SDouglas Gilbert 		if (!sd_dp->init_wq) {
441810bde980SDouglas Gilbert 			sd_dp->init_wq = true;
4419a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4420c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4421c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4422a10bc12aSDouglas Gilbert 			INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
4423cbf67842SDouglas Gilbert 		}
4424c4837394SDouglas Gilbert 		if (sdebug_statistics)
4425c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
442610bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_WQ;
4427a10bc12aSDouglas Gilbert 		schedule_work(&sd_dp->ew.work);
4428cbf67842SDouglas Gilbert 	}
4429f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4430f46eb0e9SDouglas Gilbert 		     (scsi_result == device_qfull_result)))
4431cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4432cbf67842SDouglas Gilbert 			    "%s: num_in_q=%d +1, %s%s\n", __func__,
4433cbf67842SDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""),
4434cbf67842SDouglas Gilbert 			    "status: TASK SET FULL");
44351da177e4SLinus Torvalds 	return 0;
4436cd62b7daSDouglas Gilbert 
4437cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
4438cd62b7daSDouglas Gilbert 	cmnd->result = scsi_result;
4439cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
4440cd62b7daSDouglas Gilbert 	return 0;
44411da177e4SLinus Torvalds }
4442cbf67842SDouglas Gilbert 
444323183910SDouglas Gilbert /* Note: The following macros create attribute files in the
444423183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
444523183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
444623183910SDouglas Gilbert    as it can when the corresponding attribute in the
444723183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
444823183910SDouglas Gilbert  */
4449773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4450773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
44519b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
4452773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
4453c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
4454773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4455773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
4456773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
4457773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4458773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4459773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4460773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4461773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
4462e5203cf0SHannes Reinecke module_param_string(inq_vendor, sdebug_inq_vendor_id,
4463e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR);
4464e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
4465e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR);
4466e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
4467e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR);
4468773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4469773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4470773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4471773642d9SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4472773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4473773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4474773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4475d9da891aSLaurence Oberman module_param_named(medium_error_start, sdebug_medium_error_start, int, S_IRUGO | S_IWUSR);
4476d9da891aSLaurence Oberman module_param_named(medium_error_count, sdebug_medium_error_count, int, S_IRUGO | S_IWUSR);
4477773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4478773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4479773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4480773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4481773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4482773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4483773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4484773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
448586e6828aSLukas Herbolt module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
4486773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4487773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4488773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4489773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
4490c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
4491773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
4492c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
4493773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4494773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4495773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4496773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4497773642d9SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
449809ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
4499773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
450023183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
4501773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
45025b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
45031da177e4SLinus Torvalds 
45041da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
45051da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
45061da177e4SLinus Torvalds MODULE_LICENSE("GPL");
4507b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
45081da177e4SLinus Torvalds 
45091da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
45105b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
45119b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
45120759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
4513cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
4514c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
45155b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
45165b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
4517c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
4518beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
451923183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
45205b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
4521185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
4522e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
4523e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
45249b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
45259b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
45265b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
45275b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
45285b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
4529760f3b03SDouglas Gilbert MODULE_PARM_DESC(lbprz,
4530760f3b03SDouglas Gilbert 	"on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
45315b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
4532c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
4533cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4534d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
4535d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
4536cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
4537c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
453878d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
45391da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
4540c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
454132c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
45426f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
45435b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
454486e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
45451da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
4546d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
4547760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
4548ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
4549c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
4550c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
4551c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
45525b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
45535b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
45546014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
45556014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
455609ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
455709ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
4558c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
45595b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
45605b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
45611da177e4SLinus Torvalds 
4562760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
4563760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
45641da177e4SLinus Torvalds 
45651da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp)
45661da177e4SLinus Torvalds {
4567c4837394SDouglas Gilbert 	int k;
4568c4837394SDouglas Gilbert 
4569760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4570760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
4571760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
4572c4837394SDouglas Gilbert 		return sdebug_info;
4573760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4574760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4575760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
4576760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
45771da177e4SLinus Torvalds 	return sdebug_info;
45781da177e4SLinus Torvalds }
45791da177e4SLinus Torvalds 
4580cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
4581fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4582fd32119bSDouglas Gilbert 				 int length)
45831da177e4SLinus Torvalds {
45841da177e4SLinus Torvalds 	char arr[16];
4585c8ed555aSAl Viro 	int opts;
45861da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
45871da177e4SLinus Torvalds 
45881da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
45891da177e4SLinus Torvalds 		return -EACCES;
45901da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
45911da177e4SLinus Torvalds 	arr[minLen] = '\0';
4592c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
45931da177e4SLinus Torvalds 		return -EINVAL;
4594773642d9SDouglas Gilbert 	sdebug_opts = opts;
4595773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4596773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4597773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
4598c4837394SDouglas Gilbert 		tweak_cmnd_count();
45991da177e4SLinus Torvalds 	return length;
46001da177e4SLinus Torvalds }
4601c8ed555aSAl Viro 
4602cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4603cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
4604cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
4605c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4606c8ed555aSAl Viro {
4607c4837394SDouglas Gilbert 	int f, j, l;
4608c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4609cbf67842SDouglas Gilbert 
4610c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4611c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
4612c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4613c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4614c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
4615c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4616c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4617c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
4618c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4619c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4620c4837394SDouglas Gilbert 		   num_aborts);
4621c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4622c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
4623c4837394SDouglas Gilbert 		   num_host_resets);
4624c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4625c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
4626458df78bSBart Van Assche 	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
4627458df78bSBart Van Assche 		   sdebug_statistics);
4628c4837394SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4629c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
4630c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
4631c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
4632c4837394SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf));
4633cbf67842SDouglas Gilbert 
4634c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
4635c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4636c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
4637c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4638773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
4639c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4640c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
4641c4837394SDouglas Gilbert 				   "first,last bits", f, l);
4642c4837394SDouglas Gilbert 		}
4643cbf67842SDouglas Gilbert 	}
4644c8ed555aSAl Viro 	return 0;
46451da177e4SLinus Torvalds }
46461da177e4SLinus Torvalds 
464782069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
46481da177e4SLinus Torvalds {
4649c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
46501da177e4SLinus Torvalds }
4651c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4652c4837394SDouglas Gilbert  * of delay is jiffies.
4653c4837394SDouglas Gilbert  */
465482069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
465582069379SAkinobu Mita 			   size_t count)
46561da177e4SLinus Torvalds {
4657c2206098SDouglas Gilbert 	int jdelay, res;
46581da177e4SLinus Torvalds 
4659b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
4660cbf67842SDouglas Gilbert 		res = count;
4661c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
4662c4837394SDouglas Gilbert 			int j, k;
4663c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4664cbf67842SDouglas Gilbert 
4665c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4666c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4667c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4668c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4669c4837394SDouglas Gilbert 						   sdebug_max_queue);
4670c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4671c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4672c4837394SDouglas Gilbert 					break;
4673c4837394SDouglas Gilbert 				}
4674c4837394SDouglas Gilbert 			}
4675c4837394SDouglas Gilbert 			if (res > 0) {
4676c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
4677773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
46781da177e4SLinus Torvalds 			}
4679c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4680cbf67842SDouglas Gilbert 		}
4681cbf67842SDouglas Gilbert 		return res;
46821da177e4SLinus Torvalds 	}
46831da177e4SLinus Torvalds 	return -EINVAL;
46841da177e4SLinus Torvalds }
468582069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
46861da177e4SLinus Torvalds 
4687cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4688cbf67842SDouglas Gilbert {
4689773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
4690cbf67842SDouglas Gilbert }
4691cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
4692c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
4693cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
4694cbf67842SDouglas Gilbert 			    size_t count)
4695cbf67842SDouglas Gilbert {
4696c4837394SDouglas Gilbert 	int ndelay, res;
4697cbf67842SDouglas Gilbert 
4698cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4699c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
4700cbf67842SDouglas Gilbert 		res = count;
4701773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
4702c4837394SDouglas Gilbert 			int j, k;
4703c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4704c4837394SDouglas Gilbert 
4705c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4706c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4707c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4708c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4709c4837394SDouglas Gilbert 						   sdebug_max_queue);
4710c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4711c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4712c4837394SDouglas Gilbert 					break;
4713c4837394SDouglas Gilbert 				}
4714c4837394SDouglas Gilbert 			}
4715c4837394SDouglas Gilbert 			if (res > 0) {
4716773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
4717c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
4718c2206098SDouglas Gilbert 							: DEF_JDELAY;
4719cbf67842SDouglas Gilbert 			}
4720c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4721cbf67842SDouglas Gilbert 		}
4722cbf67842SDouglas Gilbert 		return res;
4723cbf67842SDouglas Gilbert 	}
4724cbf67842SDouglas Gilbert 	return -EINVAL;
4725cbf67842SDouglas Gilbert }
4726cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
4727cbf67842SDouglas Gilbert 
472882069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
47291da177e4SLinus Torvalds {
4730773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
47311da177e4SLinus Torvalds }
47321da177e4SLinus Torvalds 
473382069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
473482069379SAkinobu Mita 			  size_t count)
47351da177e4SLinus Torvalds {
47361da177e4SLinus Torvalds 	int opts;
47371da177e4SLinus Torvalds 	char work[20];
47381da177e4SLinus Torvalds 
47399a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
47409a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
47419a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
47421da177e4SLinus Torvalds 				goto opts_done;
47431da177e4SLinus Torvalds 		} else {
47449a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
47451da177e4SLinus Torvalds 				goto opts_done;
47461da177e4SLinus Torvalds 		}
47471da177e4SLinus Torvalds 	}
47481da177e4SLinus Torvalds 	return -EINVAL;
47491da177e4SLinus Torvalds opts_done:
4750773642d9SDouglas Gilbert 	sdebug_opts = opts;
4751773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4752773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4753c4837394SDouglas Gilbert 	tweak_cmnd_count();
47541da177e4SLinus Torvalds 	return count;
47551da177e4SLinus Torvalds }
475682069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
47571da177e4SLinus Torvalds 
475882069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
47591da177e4SLinus Torvalds {
4760773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
47611da177e4SLinus Torvalds }
476282069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
476382069379SAkinobu Mita 			   size_t count)
47641da177e4SLinus Torvalds {
47651da177e4SLinus Torvalds 	int n;
47661da177e4SLinus Torvalds 
47671da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4768773642d9SDouglas Gilbert 		sdebug_ptype = n;
47691da177e4SLinus Torvalds 		return count;
47701da177e4SLinus Torvalds 	}
47711da177e4SLinus Torvalds 	return -EINVAL;
47721da177e4SLinus Torvalds }
477382069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
47741da177e4SLinus Torvalds 
477582069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
47761da177e4SLinus Torvalds {
4777773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
47781da177e4SLinus Torvalds }
477982069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
478082069379SAkinobu Mita 			    size_t count)
47811da177e4SLinus Torvalds {
47821da177e4SLinus Torvalds 	int n;
47831da177e4SLinus Torvalds 
47841da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4785773642d9SDouglas Gilbert 		sdebug_dsense = n;
47861da177e4SLinus Torvalds 		return count;
47871da177e4SLinus Torvalds 	}
47881da177e4SLinus Torvalds 	return -EINVAL;
47891da177e4SLinus Torvalds }
479082069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
47911da177e4SLinus Torvalds 
479282069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
479323183910SDouglas Gilbert {
4794773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
479523183910SDouglas Gilbert }
479682069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
479782069379SAkinobu Mita 			     size_t count)
479823183910SDouglas Gilbert {
479923183910SDouglas Gilbert 	int n;
480023183910SDouglas Gilbert 
480123183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4802cbf67842SDouglas Gilbert 		n = (n > 0);
4803773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
4804773642d9SDouglas Gilbert 		if (sdebug_fake_rw != n) {
4805cbf67842SDouglas Gilbert 			if ((0 == n) && (NULL == fake_storep)) {
4806cbf67842SDouglas Gilbert 				unsigned long sz =
4807773642d9SDouglas Gilbert 					(unsigned long)sdebug_dev_size_mb *
4808cbf67842SDouglas Gilbert 					1048576;
4809cbf67842SDouglas Gilbert 
4810cbf67842SDouglas Gilbert 				fake_storep = vmalloc(sz);
4811cbf67842SDouglas Gilbert 				if (NULL == fake_storep) {
4812c1287970STomas Winkler 					pr_err("out of memory, 9\n");
4813cbf67842SDouglas Gilbert 					return -ENOMEM;
4814cbf67842SDouglas Gilbert 				}
4815cbf67842SDouglas Gilbert 				memset(fake_storep, 0, sz);
4816cbf67842SDouglas Gilbert 			}
4817773642d9SDouglas Gilbert 			sdebug_fake_rw = n;
4818cbf67842SDouglas Gilbert 		}
481923183910SDouglas Gilbert 		return count;
482023183910SDouglas Gilbert 	}
482123183910SDouglas Gilbert 	return -EINVAL;
482223183910SDouglas Gilbert }
482382069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
482423183910SDouglas Gilbert 
482582069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
4826c65b1445SDouglas Gilbert {
4827773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
4828c65b1445SDouglas Gilbert }
482982069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
483082069379SAkinobu Mita 			      size_t count)
4831c65b1445SDouglas Gilbert {
4832c65b1445SDouglas Gilbert 	int n;
4833c65b1445SDouglas Gilbert 
4834c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4835773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
4836c65b1445SDouglas Gilbert 		return count;
4837c65b1445SDouglas Gilbert 	}
4838c65b1445SDouglas Gilbert 	return -EINVAL;
4839c65b1445SDouglas Gilbert }
484082069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
4841c65b1445SDouglas Gilbert 
484282069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
48431da177e4SLinus Torvalds {
4844773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
48451da177e4SLinus Torvalds }
484682069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
484782069379SAkinobu Mita 			      size_t count)
48481da177e4SLinus Torvalds {
48491da177e4SLinus Torvalds 	int n;
48501da177e4SLinus Torvalds 
48511da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4852773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
48531da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
48541da177e4SLinus Torvalds 		return count;
48551da177e4SLinus Torvalds 	}
48561da177e4SLinus Torvalds 	return -EINVAL;
48571da177e4SLinus Torvalds }
485882069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
48591da177e4SLinus Torvalds 
486082069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
48611da177e4SLinus Torvalds {
4862773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
48631da177e4SLinus Torvalds }
486482069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
48651da177e4SLinus Torvalds 
486682069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
48671da177e4SLinus Torvalds {
4868773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
48691da177e4SLinus Torvalds }
487082069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
48711da177e4SLinus Torvalds 
487282069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
48731da177e4SLinus Torvalds {
4874773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
48751da177e4SLinus Torvalds }
487682069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
487782069379SAkinobu Mita 			       size_t count)
48781da177e4SLinus Torvalds {
48791da177e4SLinus Torvalds 	int nth;
48801da177e4SLinus Torvalds 
48811da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
4882773642d9SDouglas Gilbert 		sdebug_every_nth = nth;
4883c4837394SDouglas Gilbert 		if (nth && !sdebug_statistics) {
4884c4837394SDouglas Gilbert 			pr_info("every_nth needs statistics=1, set it\n");
4885c4837394SDouglas Gilbert 			sdebug_statistics = true;
4886c4837394SDouglas Gilbert 		}
4887c4837394SDouglas Gilbert 		tweak_cmnd_count();
48881da177e4SLinus Torvalds 		return count;
48891da177e4SLinus Torvalds 	}
48901da177e4SLinus Torvalds 	return -EINVAL;
48911da177e4SLinus Torvalds }
489282069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
48931da177e4SLinus Torvalds 
489482069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
48951da177e4SLinus Torvalds {
4896773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
48971da177e4SLinus Torvalds }
489882069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
489982069379SAkinobu Mita 			      size_t count)
49001da177e4SLinus Torvalds {
49011da177e4SLinus Torvalds 	int n;
490219c8ead7SEwan D. Milne 	bool changed;
49031da177e4SLinus Torvalds 
49041da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
49058d039e22SDouglas Gilbert 		if (n > 256) {
49068d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
49078d039e22SDouglas Gilbert 			return -EINVAL;
49088d039e22SDouglas Gilbert 		}
4909773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
4910773642d9SDouglas Gilbert 		sdebug_max_luns = n;
49111da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
4912773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
491319c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
491419c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
491519c8ead7SEwan D. Milne 
491619c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
491719c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
491819c8ead7SEwan D. Milne 					    host_list) {
491919c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
492019c8ead7SEwan D. Milne 						    dev_list) {
492119c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
492219c8ead7SEwan D. Milne 						dp->uas_bm);
492319c8ead7SEwan D. Milne 				}
492419c8ead7SEwan D. Milne 			}
492519c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
492619c8ead7SEwan D. Milne 		}
49271da177e4SLinus Torvalds 		return count;
49281da177e4SLinus Torvalds 	}
49291da177e4SLinus Torvalds 	return -EINVAL;
49301da177e4SLinus Torvalds }
493182069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
49321da177e4SLinus Torvalds 
493382069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
493478d4e5a0SDouglas Gilbert {
4935773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
493678d4e5a0SDouglas Gilbert }
4937cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
4938cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
493982069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
494082069379SAkinobu Mita 			       size_t count)
494178d4e5a0SDouglas Gilbert {
4942c4837394SDouglas Gilbert 	int j, n, k, a;
4943c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
494478d4e5a0SDouglas Gilbert 
494578d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
4946c4837394SDouglas Gilbert 	    (n <= SDEBUG_CANQUEUE)) {
4947c4837394SDouglas Gilbert 		block_unblock_all_queues(true);
4948c4837394SDouglas Gilbert 		k = 0;
4949c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4950c4837394SDouglas Gilbert 		     ++j, ++sqp) {
4951c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4952c4837394SDouglas Gilbert 			if (a > k)
4953c4837394SDouglas Gilbert 				k = a;
4954c4837394SDouglas Gilbert 		}
4955773642d9SDouglas Gilbert 		sdebug_max_queue = n;
4956c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
4957cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4958cbf67842SDouglas Gilbert 		else if (k >= n)
4959cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4960cbf67842SDouglas Gilbert 		else
4961cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4962c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
496378d4e5a0SDouglas Gilbert 		return count;
496478d4e5a0SDouglas Gilbert 	}
496578d4e5a0SDouglas Gilbert 	return -EINVAL;
496678d4e5a0SDouglas Gilbert }
496782069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
496878d4e5a0SDouglas Gilbert 
496982069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
497078d4e5a0SDouglas Gilbert {
4971773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
497278d4e5a0SDouglas Gilbert }
497382069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
497478d4e5a0SDouglas Gilbert 
497582069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
49761da177e4SLinus Torvalds {
4977773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
49781da177e4SLinus Torvalds }
497982069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
49801da177e4SLinus Torvalds 
498182069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
4982c65b1445SDouglas Gilbert {
4983773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
4984c65b1445SDouglas Gilbert }
498582069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
498682069379SAkinobu Mita 				size_t count)
4987c65b1445SDouglas Gilbert {
4988c65b1445SDouglas Gilbert 	int n;
49890d01c5dfSDouglas Gilbert 	bool changed;
4990c65b1445SDouglas Gilbert 
4991c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4992773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
4993773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
499428898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
49950d01c5dfSDouglas Gilbert 		if (changed) {
49960d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
49970d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
499828898873SFUJITA Tomonori 
49994bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
50000d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
50010d01c5dfSDouglas Gilbert 					    host_list) {
50020d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
50030d01c5dfSDouglas Gilbert 						    dev_list) {
50040d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
50050d01c5dfSDouglas Gilbert 						dp->uas_bm);
50060d01c5dfSDouglas Gilbert 				}
50070d01c5dfSDouglas Gilbert 			}
50084bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
50090d01c5dfSDouglas Gilbert 		}
5010c65b1445SDouglas Gilbert 		return count;
5011c65b1445SDouglas Gilbert 	}
5012c65b1445SDouglas Gilbert 	return -EINVAL;
5013c65b1445SDouglas Gilbert }
501482069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
5015c65b1445SDouglas Gilbert 
501682069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
50171da177e4SLinus Torvalds {
5018773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
50191da177e4SLinus Torvalds }
50201da177e4SLinus Torvalds 
5021fd32119bSDouglas Gilbert static int sdebug_add_adapter(void);
5022fd32119bSDouglas Gilbert static void sdebug_remove_adapter(void);
5023fd32119bSDouglas Gilbert 
502482069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
502582069379SAkinobu Mita 			      size_t count)
50261da177e4SLinus Torvalds {
50271da177e4SLinus Torvalds 	int delta_hosts;
50281da177e4SLinus Torvalds 
5029f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
50301da177e4SLinus Torvalds 		return -EINVAL;
50311da177e4SLinus Torvalds 	if (delta_hosts > 0) {
50321da177e4SLinus Torvalds 		do {
50331da177e4SLinus Torvalds 			sdebug_add_adapter();
50341da177e4SLinus Torvalds 		} while (--delta_hosts);
50351da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
50361da177e4SLinus Torvalds 		do {
50371da177e4SLinus Torvalds 			sdebug_remove_adapter();
50381da177e4SLinus Torvalds 		} while (++delta_hosts);
50391da177e4SLinus Torvalds 	}
50401da177e4SLinus Torvalds 	return count;
50411da177e4SLinus Torvalds }
504282069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
50431da177e4SLinus Torvalds 
504482069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
504523183910SDouglas Gilbert {
5046773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
504723183910SDouglas Gilbert }
504882069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
504982069379SAkinobu Mita 				    size_t count)
505023183910SDouglas Gilbert {
505123183910SDouglas Gilbert 	int n;
505223183910SDouglas Gilbert 
505323183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5054773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
505523183910SDouglas Gilbert 		return count;
505623183910SDouglas Gilbert 	}
505723183910SDouglas Gilbert 	return -EINVAL;
505823183910SDouglas Gilbert }
505982069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
506023183910SDouglas Gilbert 
5061c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
5062c4837394SDouglas Gilbert {
5063c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
5064c4837394SDouglas Gilbert }
5065c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
5066c4837394SDouglas Gilbert 				size_t count)
5067c4837394SDouglas Gilbert {
5068c4837394SDouglas Gilbert 	int n;
5069c4837394SDouglas Gilbert 
5070c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
5071c4837394SDouglas Gilbert 		if (n > 0)
5072c4837394SDouglas Gilbert 			sdebug_statistics = true;
5073c4837394SDouglas Gilbert 		else {
5074c4837394SDouglas Gilbert 			clear_queue_stats();
5075c4837394SDouglas Gilbert 			sdebug_statistics = false;
5076c4837394SDouglas Gilbert 		}
5077c4837394SDouglas Gilbert 		return count;
5078c4837394SDouglas Gilbert 	}
5079c4837394SDouglas Gilbert 	return -EINVAL;
5080c4837394SDouglas Gilbert }
5081c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
5082c4837394SDouglas Gilbert 
508382069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
5084597136abSMartin K. Petersen {
5085773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
5086597136abSMartin K. Petersen }
508782069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
5088597136abSMartin K. Petersen 
5089c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
5090c4837394SDouglas Gilbert {
5091c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
5092c4837394SDouglas Gilbert }
5093c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
5094c4837394SDouglas Gilbert 
509582069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
5096c6a44287SMartin K. Petersen {
5097773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
5098c6a44287SMartin K. Petersen }
509982069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
5100c6a44287SMartin K. Petersen 
510182069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
5102c6a44287SMartin K. Petersen {
5103773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
5104c6a44287SMartin K. Petersen }
510582069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
5106c6a44287SMartin K. Petersen 
510782069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
5108c6a44287SMartin K. Petersen {
5109773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
5110c6a44287SMartin K. Petersen }
511182069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
5112c6a44287SMartin K. Petersen 
511382069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
5114c6a44287SMartin K. Petersen {
5115773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
5116c6a44287SMartin K. Petersen }
511782069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
5118c6a44287SMartin K. Petersen 
511982069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
512044d92694SMartin K. Petersen {
512144d92694SMartin K. Petersen 	ssize_t count;
512244d92694SMartin K. Petersen 
51235b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
512444d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
512544d92694SMartin K. Petersen 				 sdebug_store_sectors);
512644d92694SMartin K. Petersen 
5127c7badc90STejun Heo 	count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
5128c7badc90STejun Heo 			  (int)map_size, map_storep);
512944d92694SMartin K. Petersen 	buf[count++] = '\n';
5130c7badc90STejun Heo 	buf[count] = '\0';
513144d92694SMartin K. Petersen 
513244d92694SMartin K. Petersen 	return count;
513344d92694SMartin K. Petersen }
513482069379SAkinobu Mita static DRIVER_ATTR_RO(map);
513544d92694SMartin K. Petersen 
513682069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
5137d986788bSMartin Pitt {
5138773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
5139d986788bSMartin Pitt }
514082069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
514182069379SAkinobu Mita 			       size_t count)
5142d986788bSMartin Pitt {
5143d986788bSMartin Pitt 	int n;
5144d986788bSMartin Pitt 
5145d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5146773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
5147d986788bSMartin Pitt 		return count;
5148d986788bSMartin Pitt 	}
5149d986788bSMartin Pitt 	return -EINVAL;
5150d986788bSMartin Pitt }
515182069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
5152d986788bSMartin Pitt 
5153cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
5154cbf67842SDouglas Gilbert {
5155773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
5156cbf67842SDouglas Gilbert }
5157185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
5158cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
5159cbf67842SDouglas Gilbert 			       size_t count)
5160cbf67842SDouglas Gilbert {
5161185dd232SDouglas Gilbert 	int n;
5162cbf67842SDouglas Gilbert 
5163cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5164185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
5165185dd232SDouglas Gilbert 		return count;
5166cbf67842SDouglas Gilbert 	}
5167cbf67842SDouglas Gilbert 	return -EINVAL;
5168cbf67842SDouglas Gilbert }
5169cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
5170cbf67842SDouglas Gilbert 
5171c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
5172c2248fc9SDouglas Gilbert {
5173773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
5174c2248fc9SDouglas Gilbert }
5175c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
5176c2248fc9SDouglas Gilbert 			    size_t count)
5177c2248fc9SDouglas Gilbert {
5178c2248fc9SDouglas Gilbert 	int n;
5179c2248fc9SDouglas Gilbert 
5180c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5181773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
5182c2248fc9SDouglas Gilbert 		return count;
5183c2248fc9SDouglas Gilbert 	}
5184c2248fc9SDouglas Gilbert 	return -EINVAL;
5185c2248fc9SDouglas Gilbert }
5186c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
5187c2248fc9SDouglas Gilbert 
518809ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
518909ba24c1SDouglas Gilbert {
519009ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
519109ba24c1SDouglas Gilbert }
519209ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
519309ba24c1SDouglas Gilbert 
51949b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
51959b760fd8SDouglas Gilbert {
51969b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
51979b760fd8SDouglas Gilbert }
51989b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
51999b760fd8SDouglas Gilbert 			     size_t count)
52009b760fd8SDouglas Gilbert {
52019b760fd8SDouglas Gilbert 	int ret, n;
52029b760fd8SDouglas Gilbert 
52039b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
52049b760fd8SDouglas Gilbert 	if (ret)
52059b760fd8SDouglas Gilbert 		return ret;
52069b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
52079b760fd8SDouglas Gilbert 	all_config_cdb_len();
52089b760fd8SDouglas Gilbert 	return count;
52099b760fd8SDouglas Gilbert }
52109b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
52119b760fd8SDouglas Gilbert 
5212cbf67842SDouglas Gilbert 
521382069379SAkinobu Mita /* Note: The following array creates attribute files in the
521423183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
521523183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
521623183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
521723183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
521823183910SDouglas Gilbert  */
52196ecaff7fSRandy Dunlap 
522082069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
522182069379SAkinobu Mita 	&driver_attr_delay.attr,
522282069379SAkinobu Mita 	&driver_attr_opts.attr,
522382069379SAkinobu Mita 	&driver_attr_ptype.attr,
522482069379SAkinobu Mita 	&driver_attr_dsense.attr,
522582069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
522682069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
522782069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
522882069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
522982069379SAkinobu Mita 	&driver_attr_num_parts.attr,
523082069379SAkinobu Mita 	&driver_attr_every_nth.attr,
523182069379SAkinobu Mita 	&driver_attr_max_luns.attr,
523282069379SAkinobu Mita 	&driver_attr_max_queue.attr,
523382069379SAkinobu Mita 	&driver_attr_no_uld.attr,
523482069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
523582069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
523682069379SAkinobu Mita 	&driver_attr_add_host.attr,
523782069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
523882069379SAkinobu Mita 	&driver_attr_sector_size.attr,
5239c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
5240c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
524182069379SAkinobu Mita 	&driver_attr_dix.attr,
524282069379SAkinobu Mita 	&driver_attr_dif.attr,
524382069379SAkinobu Mita 	&driver_attr_guard.attr,
524482069379SAkinobu Mita 	&driver_attr_ato.attr,
524582069379SAkinobu Mita 	&driver_attr_map.attr,
524682069379SAkinobu Mita 	&driver_attr_removable.attr,
5247cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
5248cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
5249c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
525009ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
52519b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
525282069379SAkinobu Mita 	NULL,
525382069379SAkinobu Mita };
525482069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
52551da177e4SLinus Torvalds 
525611ddcecaSAkinobu Mita static struct device *pseudo_primary;
52578dea0d02SFUJITA Tomonori 
52581da177e4SLinus Torvalds static int __init scsi_debug_init(void)
52591da177e4SLinus Torvalds {
52605f2578e5SFUJITA Tomonori 	unsigned long sz;
52611da177e4SLinus Torvalds 	int host_to_add;
52621da177e4SLinus Torvalds 	int k;
52636ecaff7fSRandy Dunlap 	int ret;
52641da177e4SLinus Torvalds 
5265cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
5266cbf67842SDouglas Gilbert 
5267773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
5268c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
5269773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
5270773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
5271c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
5272cbf67842SDouglas Gilbert 
5273773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
5274597136abSMartin K. Petersen 	case  512:
5275597136abSMartin K. Petersen 	case 1024:
5276597136abSMartin K. Petersen 	case 2048:
5277597136abSMartin K. Petersen 	case 4096:
5278597136abSMartin K. Petersen 		break;
5279597136abSMartin K. Petersen 	default:
5280773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
5281597136abSMartin K. Petersen 		return -EINVAL;
5282597136abSMartin K. Petersen 	}
5283597136abSMartin K. Petersen 
5284773642d9SDouglas Gilbert 	switch (sdebug_dif) {
52858475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
5286f46eb0e9SDouglas Gilbert 		break;
52878475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
52888475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
52898475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
5290f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
5291c6a44287SMartin K. Petersen 		break;
5292c6a44287SMartin K. Petersen 
5293c6a44287SMartin K. Petersen 	default:
5294c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
5295c6a44287SMartin K. Petersen 		return -EINVAL;
5296c6a44287SMartin K. Petersen 	}
5297c6a44287SMartin K. Petersen 
5298773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
5299c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
5300c6a44287SMartin K. Petersen 		return -EINVAL;
5301c6a44287SMartin K. Petersen 	}
5302c6a44287SMartin K. Petersen 
5303773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
5304c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
5305c6a44287SMartin K. Petersen 		return -EINVAL;
5306c6a44287SMartin K. Petersen 	}
5307c6a44287SMartin K. Petersen 
5308773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
5309773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
5310ea61fca5SMartin K. Petersen 		return -EINVAL;
5311ea61fca5SMartin K. Petersen 	}
53128d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
53138d039e22SDouglas Gilbert 		pr_warn("max_luns can be no more than 256, use default\n");
53148d039e22SDouglas Gilbert 		sdebug_max_luns = DEF_MAX_LUNS;
53158d039e22SDouglas Gilbert 	}
5316ea61fca5SMartin K. Petersen 
5317773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
5318773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
5319ea61fca5SMartin K. Petersen 		return -EINVAL;
5320ea61fca5SMartin K. Petersen 	}
5321ea61fca5SMartin K. Petersen 
5322c4837394SDouglas Gilbert 	if (submit_queues < 1) {
5323c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
5324c4837394SDouglas Gilbert 		return -EINVAL;
5325c4837394SDouglas Gilbert 	}
5326c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
5327c4837394SDouglas Gilbert 			       GFP_KERNEL);
5328c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
5329c4837394SDouglas Gilbert 		return -ENOMEM;
5330c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
5331c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
5332c4837394SDouglas Gilbert 
5333773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
5334773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
5335773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
5336773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
533728898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
53381da177e4SLinus Torvalds 
53391da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
53401da177e4SLinus Torvalds 	sdebug_heads = 8;
53411da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
5342773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
53431da177e4SLinus Torvalds 		sdebug_heads = 64;
5344773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
5345fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
53461da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
53471da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
53481da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
53491da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
53501da177e4SLinus Torvalds 		sdebug_heads = 255;
53511da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
53521da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
53531da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
53541da177e4SLinus Torvalds 	}
53551da177e4SLinus Torvalds 
5356b01f6f83SDouglas Gilbert 	if (sdebug_fake_rw == 0) {
53571da177e4SLinus Torvalds 		fake_storep = vmalloc(sz);
53581da177e4SLinus Torvalds 		if (NULL == fake_storep) {
5359c1287970STomas Winkler 			pr_err("out of memory, 1\n");
5360c4837394SDouglas Gilbert 			ret = -ENOMEM;
5361c4837394SDouglas Gilbert 			goto free_q_arr;
53621da177e4SLinus Torvalds 		}
53631da177e4SLinus Torvalds 		memset(fake_storep, 0, sz);
5364773642d9SDouglas Gilbert 		if (sdebug_num_parts > 0)
5365f58b0efbSFUJITA Tomonori 			sdebug_build_parts(fake_storep, sz);
5366cbf67842SDouglas Gilbert 	}
53671da177e4SLinus Torvalds 
5368773642d9SDouglas Gilbert 	if (sdebug_dix) {
5369c6a44287SMartin K. Petersen 		int dif_size;
5370c6a44287SMartin K. Petersen 
53716ebf105cSChristoph Hellwig 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
5372c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
5373c6a44287SMartin K. Petersen 
5374c1287970STomas Winkler 		pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
5375c6a44287SMartin K. Petersen 
5376c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
5377c1287970STomas Winkler 			pr_err("out of mem. (DIX)\n");
5378c6a44287SMartin K. Petersen 			ret = -ENOMEM;
5379c6a44287SMartin K. Petersen 			goto free_vm;
5380c6a44287SMartin K. Petersen 		}
5381c6a44287SMartin K. Petersen 
5382c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
5383c6a44287SMartin K. Petersen 	}
5384c6a44287SMartin K. Petersen 
53855b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
53865b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
5387773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
5388773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
53896014759cSMartin K. Petersen 
5390773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
5391773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
53926014759cSMartin K. Petersen 
5393773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
5394773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
53956014759cSMartin K. Petersen 
5396773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
5397773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
5398773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
5399c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
5400c4837394SDouglas Gilbert 			ret = -EINVAL;
5401c4837394SDouglas Gilbert 			goto free_vm;
540244d92694SMartin K. Petersen 		}
540344d92694SMartin K. Petersen 
5404b90ebc3dSAkinobu Mita 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
5405b90ebc3dSAkinobu Mita 		map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
540644d92694SMartin K. Petersen 
5407c1287970STomas Winkler 		pr_info("%lu provisioning blocks\n", map_size);
540844d92694SMartin K. Petersen 
540944d92694SMartin K. Petersen 		if (map_storep == NULL) {
5410c1287970STomas Winkler 			pr_err("out of mem. (MAP)\n");
541144d92694SMartin K. Petersen 			ret = -ENOMEM;
541244d92694SMartin K. Petersen 			goto free_vm;
541344d92694SMartin K. Petersen 		}
541444d92694SMartin K. Petersen 
5415b90ebc3dSAkinobu Mita 		bitmap_zero(map_storep, map_size);
541644d92694SMartin K. Petersen 
541744d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
5418773642d9SDouglas Gilbert 		if (sdebug_num_parts)
541944d92694SMartin K. Petersen 			map_region(0, 2);
542044d92694SMartin K. Petersen 	}
542144d92694SMartin K. Petersen 
54229b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
54239b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
5424c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
54259b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
54266ecaff7fSRandy Dunlap 		goto free_vm;
54276ecaff7fSRandy Dunlap 	}
54286ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
54296ecaff7fSRandy Dunlap 	if (ret < 0) {
5430c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
54316ecaff7fSRandy Dunlap 		goto dev_unreg;
54326ecaff7fSRandy Dunlap 	}
54336ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
54346ecaff7fSRandy Dunlap 	if (ret < 0) {
5435c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
54366ecaff7fSRandy Dunlap 		goto bus_unreg;
54376ecaff7fSRandy Dunlap 	}
54381da177e4SLinus Torvalds 
5439773642d9SDouglas Gilbert 	host_to_add = sdebug_add_host;
5440773642d9SDouglas Gilbert 	sdebug_add_host = 0;
54411da177e4SLinus Torvalds 
54421da177e4SLinus Torvalds 	for (k = 0; k < host_to_add; k++) {
54431da177e4SLinus Torvalds 		if (sdebug_add_adapter()) {
5444c1287970STomas Winkler 			pr_err("sdebug_add_adapter failed k=%d\n", k);
54451da177e4SLinus Torvalds 			break;
54461da177e4SLinus Torvalds 		}
54471da177e4SLinus Torvalds 	}
54481da177e4SLinus Torvalds 
5449773642d9SDouglas Gilbert 	if (sdebug_verbose)
5450773642d9SDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_add_host);
5451c1287970STomas Winkler 
54521da177e4SLinus Torvalds 	return 0;
54536ecaff7fSRandy Dunlap 
54546ecaff7fSRandy Dunlap bus_unreg:
54556ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
54566ecaff7fSRandy Dunlap dev_unreg:
54579b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
54586ecaff7fSRandy Dunlap free_vm:
545944d92694SMartin K. Petersen 	vfree(map_storep);
5460c6a44287SMartin K. Petersen 	vfree(dif_storep);
54616ecaff7fSRandy Dunlap 	vfree(fake_storep);
5462c4837394SDouglas Gilbert free_q_arr:
5463c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
54646ecaff7fSRandy Dunlap 	return ret;
54651da177e4SLinus Torvalds }
54661da177e4SLinus Torvalds 
54671da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
54681da177e4SLinus Torvalds {
5469773642d9SDouglas Gilbert 	int k = sdebug_add_host;
54701da177e4SLinus Torvalds 
54711da177e4SLinus Torvalds 	stop_all_queued();
5472cbf67842SDouglas Gilbert 	free_all_queued();
54731da177e4SLinus Torvalds 	for (; k; k--)
54741da177e4SLinus Torvalds 		sdebug_remove_adapter();
54751da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
54761da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
54779b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
54781da177e4SLinus Torvalds 
54794d2b496fSEwan D. Milne 	vfree(map_storep);
5480c6a44287SMartin K. Petersen 	vfree(dif_storep);
54811da177e4SLinus Torvalds 	vfree(fake_storep);
5482c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
54831da177e4SLinus Torvalds }
54841da177e4SLinus Torvalds 
54851da177e4SLinus Torvalds device_initcall(scsi_debug_init);
54861da177e4SLinus Torvalds module_exit(scsi_debug_exit);
54871da177e4SLinus Torvalds 
54881da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev)
54891da177e4SLinus Torvalds {
54901da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
54911da177e4SLinus Torvalds 
54921da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
54931da177e4SLinus Torvalds 	kfree(sdbg_host);
54941da177e4SLinus Torvalds }
54951da177e4SLinus Torvalds 
54961da177e4SLinus Torvalds static int sdebug_add_adapter(void)
54971da177e4SLinus Torvalds {
54981da177e4SLinus Torvalds 	int k, devs_per_host;
54991da177e4SLinus Torvalds 	int error = 0;
55001da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
55018b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
55021da177e4SLinus Torvalds 
550324669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
55049a051019SDouglas Gilbert 	if (sdbg_host == NULL) {
5505c1287970STomas Winkler 		pr_err("out of memory at line %d\n", __LINE__);
55061da177e4SLinus Torvalds 		return -ENOMEM;
55071da177e4SLinus Torvalds 	}
55081da177e4SLinus Torvalds 
55091da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
55101da177e4SLinus Torvalds 
5511773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
55121da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
55135cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
55145cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
5515c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
55161da177e4SLinus Torvalds 			error = -ENOMEM;
55171da177e4SLinus Torvalds 			goto clean;
55181da177e4SLinus Torvalds 		}
55191da177e4SLinus Torvalds 	}
55201da177e4SLinus Torvalds 
55211da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
55221da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
55231da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
55241da177e4SLinus Torvalds 
55251da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
55269b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
55271da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
5528773642d9SDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
55291da177e4SLinus Torvalds 
55301da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
55311da177e4SLinus Torvalds 
55321da177e4SLinus Torvalds 	if (error)
55331da177e4SLinus Torvalds 		goto clean;
55341da177e4SLinus Torvalds 
5535773642d9SDouglas Gilbert 	++sdebug_add_host;
55361da177e4SLinus Torvalds 	return error;
55371da177e4SLinus Torvalds 
55381da177e4SLinus Torvalds clean:
55398b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
55408b40228fSFUJITA Tomonori 				 dev_list) {
55411da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
55421da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
55431da177e4SLinus Torvalds 	}
55441da177e4SLinus Torvalds 
55451da177e4SLinus Torvalds 	kfree(sdbg_host);
55461da177e4SLinus Torvalds 	return error;
55471da177e4SLinus Torvalds }
55481da177e4SLinus Torvalds 
55491da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
55501da177e4SLinus Torvalds {
55511da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
55521da177e4SLinus Torvalds 
55531da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
55541da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
55551da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
55561da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
55571da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
55581da177e4SLinus Torvalds 	}
55591da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
55601da177e4SLinus Torvalds 
55611da177e4SLinus Torvalds 	if (!sdbg_host)
55621da177e4SLinus Torvalds 		return;
55631da177e4SLinus Torvalds 
55641da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
5565773642d9SDouglas Gilbert 	--sdebug_add_host;
55661da177e4SLinus Torvalds }
55671da177e4SLinus Torvalds 
5568fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
5569cbf67842SDouglas Gilbert {
5570cbf67842SDouglas Gilbert 	int num_in_q = 0;
5571cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5572cbf67842SDouglas Gilbert 
5573c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
5574cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
5575cbf67842SDouglas Gilbert 	if (NULL == devip) {
5576c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
5577cbf67842SDouglas Gilbert 		return	-ENODEV;
5578cbf67842SDouglas Gilbert 	}
5579cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5580c40ecc12SChristoph Hellwig 
5581cbf67842SDouglas Gilbert 	if (qdepth < 1)
5582cbf67842SDouglas Gilbert 		qdepth = 1;
5583c4837394SDouglas Gilbert 	/* allow to exceed max host qc_arr elements for testing */
5584c4837394SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE + 10)
5585c4837394SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE + 10;
5586db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
5587cbf67842SDouglas Gilbert 
5588773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
5589c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
5590c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
5591cbf67842SDouglas Gilbert 	}
5592c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
5593cbf67842SDouglas Gilbert 	return sdev->queue_depth;
5594cbf67842SDouglas Gilbert }
5595cbf67842SDouglas Gilbert 
5596c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
5597817fd66bSDouglas Gilbert {
5598c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
5599773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
5600773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
5601773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
5602c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
5603773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
5604817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
5605c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
5606817fd66bSDouglas Gilbert 	}
5607c4837394SDouglas Gilbert 	return false;
5608817fd66bSDouglas Gilbert }
5609817fd66bSDouglas Gilbert 
56107ee6d1b4SBart Van Assche static bool fake_host_busy(struct scsi_cmnd *scp)
56117ee6d1b4SBart Van Assche {
56127ee6d1b4SBart Van Assche 	return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
56137ee6d1b4SBart Van Assche 		(atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
56147ee6d1b4SBart Van Assche }
56157ee6d1b4SBart Van Assche 
5616fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5617fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
5618c2248fc9SDouglas Gilbert {
5619c2248fc9SDouglas Gilbert 	u8 sdeb_i;
5620c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
5621c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
5622c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
5623c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
5624c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
5625c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5626c2248fc9SDouglas Gilbert 	int k, na;
5627c2248fc9SDouglas Gilbert 	int errsts = 0;
5628c2248fc9SDouglas Gilbert 	u32 flags;
5629c2248fc9SDouglas Gilbert 	u16 sa;
5630c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
5631c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
5632c2248fc9SDouglas Gilbert 
5633c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
5634c4837394SDouglas Gilbert 	if (sdebug_statistics)
5635c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
5636f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
5637f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
5638c2248fc9SDouglas Gilbert 		char b[120];
5639c2248fc9SDouglas Gilbert 		int n, len, sb;
5640c2248fc9SDouglas Gilbert 
5641c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
5642c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
5643c2248fc9SDouglas Gilbert 		if (len > 32)
5644c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
5645c2248fc9SDouglas Gilbert 		else {
5646c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
5647c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
5648c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
5649c2248fc9SDouglas Gilbert 		}
5650458df78bSBart Van Assche 		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
5651458df78bSBart Van Assche 			    blk_mq_unique_tag(scp->request), b);
5652c2248fc9SDouglas Gilbert 	}
56537ee6d1b4SBart Van Assche 	if (fake_host_busy(scp))
56547ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
565534d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
5656f46eb0e9SDouglas Gilbert 	if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5657f46eb0e9SDouglas Gilbert 		goto err_out;
5658c2248fc9SDouglas Gilbert 
5659c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
5660c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
5661c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
5662f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
5663f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5664c2248fc9SDouglas Gilbert 		if (NULL == devip)
5665f46eb0e9SDouglas Gilbert 			goto err_out;
5666c2248fc9SDouglas Gilbert 	}
5667c2248fc9SDouglas Gilbert 	na = oip->num_attached;
5668c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
5669c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
5670c2248fc9SDouglas Gilbert 		r_oip = oip;
5671c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
5672c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
5673c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
5674c2248fc9SDouglas Gilbert 			else
5675c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
5676c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5677c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
5678c2248fc9SDouglas Gilbert 					break;
5679c2248fc9SDouglas Gilbert 			}
5680c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
5681c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5682c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
5683c2248fc9SDouglas Gilbert 					break;
5684c2248fc9SDouglas Gilbert 			}
5685c2248fc9SDouglas Gilbert 		}
5686c2248fc9SDouglas Gilbert 		if (k > na) {
5687c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
5688c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5689c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
5690c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5691c2248fc9SDouglas Gilbert 			else
5692c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
5693c2248fc9SDouglas Gilbert 			goto check_cond;
5694c2248fc9SDouglas Gilbert 		}
5695c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
5696c2248fc9SDouglas Gilbert 	flags = oip->flags;
5697f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
5698c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5699c2248fc9SDouglas Gilbert 		goto check_cond;
5700c2248fc9SDouglas Gilbert 	}
5701f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
5702773642d9SDouglas Gilbert 		if (sdebug_verbose)
5703773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5704773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
5705c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5706c2248fc9SDouglas Gilbert 		goto check_cond;
5707c2248fc9SDouglas Gilbert 	}
5708f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
5709c2248fc9SDouglas Gilbert 		u8 rem;
5710c2248fc9SDouglas Gilbert 		int j;
5711c2248fc9SDouglas Gilbert 
5712c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5713c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
5714c2248fc9SDouglas Gilbert 			if (rem) {
5715c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
5716c2248fc9SDouglas Gilbert 					if (0x80 & rem)
5717c2248fc9SDouglas Gilbert 						break;
5718c2248fc9SDouglas Gilbert 				}
5719c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5720c2248fc9SDouglas Gilbert 				goto check_cond;
5721c2248fc9SDouglas Gilbert 			}
5722c2248fc9SDouglas Gilbert 		}
5723c2248fc9SDouglas Gilbert 	}
5724f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
5725b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
5726b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
5727f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
5728c2248fc9SDouglas Gilbert 		if (errsts)
5729c2248fc9SDouglas Gilbert 			goto check_cond;
5730c2248fc9SDouglas Gilbert 	}
5731c4837394SDouglas Gilbert 	if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
5732c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
5733773642d9SDouglas Gilbert 		if (sdebug_verbose)
5734c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5735c2248fc9SDouglas Gilbert 				    "%s\n", my_name, "initializing command "
5736c2248fc9SDouglas Gilbert 				    "required");
5737c2248fc9SDouglas Gilbert 		errsts = check_condition_result;
5738c2248fc9SDouglas Gilbert 		goto fini;
5739c2248fc9SDouglas Gilbert 	}
5740773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
5741c2248fc9SDouglas Gilbert 		goto fini;
5742f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
5743c4837394SDouglas Gilbert 		if (fake_timeout(scp))
5744c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
5745c2248fc9SDouglas Gilbert 	}
5746f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
5747f46eb0e9SDouglas Gilbert 		errsts = oip->pfp(scp, devip);	/* calls a resp_* function */
5748c2248fc9SDouglas Gilbert 	else if (r_pfp)	/* if leaf function ptr NULL, try the root's */
5749c2248fc9SDouglas Gilbert 		errsts = r_pfp(scp, devip);
575080c49563SDouglas Gilbert 	if (errsts & SDEG_RES_IMMED_MASK) {
575180c49563SDouglas Gilbert 		errsts &= ~SDEG_RES_IMMED_MASK;
575280c49563SDouglas Gilbert 		flags |= F_DELAY_OVERR;
575380c49563SDouglas Gilbert 		flags &= ~F_LONG_DELAY;
575480c49563SDouglas Gilbert 	}
575580c49563SDouglas Gilbert 
5756c2248fc9SDouglas Gilbert 
5757c2248fc9SDouglas Gilbert fini:
575810bde980SDouglas Gilbert 	if (F_DELAY_OVERR & flags)
575910bde980SDouglas Gilbert 		return schedule_resp(scp, devip, errsts, 0, 0);
576080c49563SDouglas Gilbert 	else if ((sdebug_jdelay || sdebug_ndelay) && (flags & F_LONG_DELAY)) {
576180c49563SDouglas Gilbert 		/*
576280c49563SDouglas Gilbert 		 * If any delay is active, want F_LONG_DELAY to be at least 1
576380c49563SDouglas Gilbert 		 * second and if sdebug_jdelay>0 want a long delay of that
576480c49563SDouglas Gilbert 		 * many seconds.
576580c49563SDouglas Gilbert 		 */
576680c49563SDouglas Gilbert 		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
576780c49563SDouglas Gilbert 
576880c49563SDouglas Gilbert 		jdelay = mult_frac(USER_HZ * jdelay, HZ, USER_HZ);
576980c49563SDouglas Gilbert 		return schedule_resp(scp, devip, errsts, jdelay, 0);
577080c49563SDouglas Gilbert 	} else
577110bde980SDouglas Gilbert 		return schedule_resp(scp, devip, errsts, sdebug_jdelay,
577210bde980SDouglas Gilbert 				     sdebug_ndelay);
5773c2248fc9SDouglas Gilbert check_cond:
577410bde980SDouglas Gilbert 	return schedule_resp(scp, devip, check_condition_result, 0, 0);
5775f46eb0e9SDouglas Gilbert err_out:
577610bde980SDouglas Gilbert 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0, 0);
5777c2248fc9SDouglas Gilbert }
5778c2248fc9SDouglas Gilbert 
57799e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
5780c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
5781c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
57829e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
57839e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
57849e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
57859e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
57869e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
57879e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
57889e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
5789185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
5790cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
57919e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
57929e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
5793cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
5794cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
57959e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
5796c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
57979e603ca0SFUJITA Tomonori 	.this_id =		7,
579865e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
5799cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
58006bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
58019e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
58029e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
5803c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
58049e603ca0SFUJITA Tomonori };
58059e603ca0SFUJITA Tomonori 
58061da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev)
58071da177e4SLinus Torvalds {
58081da177e4SLinus Torvalds 	int error = 0;
58091da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
58101da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
5811f46eb0e9SDouglas Gilbert 	int hprot;
58121da177e4SLinus Torvalds 
58131da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
58141da177e4SLinus Torvalds 
5815773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
5816773642d9SDouglas Gilbert 	if (sdebug_clustering)
58170759c666SAkinobu Mita 		sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
58181da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
58191da177e4SLinus Torvalds 	if (NULL == hpnt) {
5820c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
58211da177e4SLinus Torvalds 		error = -ENODEV;
58221da177e4SLinus Torvalds 		return error;
58231da177e4SLinus Torvalds 	}
5824c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
58259b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
5826c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
5827c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
5828c4837394SDouglas Gilbert 	}
5829c4837394SDouglas Gilbert 	/* Decide whether to tell scsi subsystem that we want mq */
5830c4837394SDouglas Gilbert 	/* Following should give the same answer for each host */
5831458df78bSBart Van Assche 	if (shost_use_blk_mq(hpnt))
5832c4837394SDouglas Gilbert 		hpnt->nr_hw_queues = submit_queues;
58331da177e4SLinus Torvalds 
58341da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
58351da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
5836773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5837773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
58381da177e4SLinus Torvalds 	else
5839773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
5840773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
5841f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
58421da177e4SLinus Torvalds 
5843f46eb0e9SDouglas Gilbert 	hprot = 0;
5844c6a44287SMartin K. Petersen 
5845773642d9SDouglas Gilbert 	switch (sdebug_dif) {
5846c6a44287SMartin K. Petersen 
58478475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
5848f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
5849773642d9SDouglas Gilbert 		if (sdebug_dix)
5850f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
5851c6a44287SMartin K. Petersen 		break;
5852c6a44287SMartin K. Petersen 
58538475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
5854f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
5855773642d9SDouglas Gilbert 		if (sdebug_dix)
5856f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
5857c6a44287SMartin K. Petersen 		break;
5858c6a44287SMartin K. Petersen 
58598475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
5860f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
5861773642d9SDouglas Gilbert 		if (sdebug_dix)
5862f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
5863c6a44287SMartin K. Petersen 		break;
5864c6a44287SMartin K. Petersen 
5865c6a44287SMartin K. Petersen 	default:
5866773642d9SDouglas Gilbert 		if (sdebug_dix)
5867f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
5868c6a44287SMartin K. Petersen 		break;
5869c6a44287SMartin K. Petersen 	}
5870c6a44287SMartin K. Petersen 
5871f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
5872c6a44287SMartin K. Petersen 
5873f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
5874c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
5875f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5876f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5877f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5878f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5879f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5880f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5881f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
5882c6a44287SMartin K. Petersen 
5883773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
5884c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5885c6a44287SMartin K. Petersen 	else
5886c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5887c6a44287SMartin K. Petersen 
5888773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5889773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
5890c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
5891c4837394SDouglas Gilbert 		sdebug_statistics = true;
58921da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
58931da177e4SLinus Torvalds 	if (error) {
5894c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
58951da177e4SLinus Torvalds 		error = -ENODEV;
58961da177e4SLinus Torvalds 		scsi_host_put(hpnt);
58971da177e4SLinus Torvalds 	} else
58981da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
58991da177e4SLinus Torvalds 
59001da177e4SLinus Torvalds 	return error;
59011da177e4SLinus Torvalds }
59021da177e4SLinus Torvalds 
59031da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *dev)
59041da177e4SLinus Torvalds {
59051da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
59068b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
59071da177e4SLinus Torvalds 
59081da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
59091da177e4SLinus Torvalds 
59101da177e4SLinus Torvalds 	if (!sdbg_host) {
5911c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
59121da177e4SLinus Torvalds 		return -ENODEV;
59131da177e4SLinus Torvalds 	}
59141da177e4SLinus Torvalds 
59151da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
59161da177e4SLinus Torvalds 
59178b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
59188b40228fSFUJITA Tomonori 				 dev_list) {
59191da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
59201da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
59211da177e4SLinus Torvalds 	}
59221da177e4SLinus Torvalds 
59231da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
59241da177e4SLinus Torvalds 	return 0;
59251da177e4SLinus Torvalds }
59261da177e4SLinus Torvalds 
59278dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
59288dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
59291da177e4SLinus Torvalds {
59308dea0d02SFUJITA Tomonori 	return 1;
59318dea0d02SFUJITA Tomonori }
59321da177e4SLinus Torvalds 
59338dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
59348dea0d02SFUJITA Tomonori 	.name = "pseudo",
59358dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
59368dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
59378dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
593882069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
59398dea0d02SFUJITA Tomonori };
5940