xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 52ab9768)
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 */
2374f2c8bf6SDouglas Gilbert #define F_SSU_DELAY		0x1000
2384f2c8bf6SDouglas Gilbert #define F_SYNC_DELAY		0x2000
239fd32119bSDouglas Gilbert 
240fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
24146f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
242fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
2434f2c8bf6SDouglas Gilbert #define F_LONG_DELAY		(F_SSU_DELAY | F_SYNC_DELAY)
244fd32119bSDouglas Gilbert 
245fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4
246fd32119bSDouglas Gilbert 
247b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32
248fd32119bSDouglas Gilbert 
249fd32119bSDouglas Gilbert 
250fd32119bSDouglas Gilbert struct sdebug_dev_info {
251fd32119bSDouglas Gilbert 	struct list_head dev_list;
252fd32119bSDouglas Gilbert 	unsigned int channel;
253fd32119bSDouglas Gilbert 	unsigned int target;
254fd32119bSDouglas Gilbert 	u64 lun;
255bf476433SChristoph Hellwig 	uuid_t lu_name;
256fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
257fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
258fd32119bSDouglas Gilbert 	atomic_t num_in_q;
259c4837394SDouglas Gilbert 	atomic_t stopped;
260fd32119bSDouglas Gilbert 	bool used;
261fd32119bSDouglas Gilbert };
262fd32119bSDouglas Gilbert 
263fd32119bSDouglas Gilbert struct sdebug_host_info {
264fd32119bSDouglas Gilbert 	struct list_head host_list;
265fd32119bSDouglas Gilbert 	struct Scsi_Host *shost;
266fd32119bSDouglas Gilbert 	struct device dev;
267fd32119bSDouglas Gilbert 	struct list_head dev_info_list;
268fd32119bSDouglas Gilbert };
269fd32119bSDouglas Gilbert 
270fd32119bSDouglas Gilbert #define to_sdebug_host(d)	\
271fd32119bSDouglas Gilbert 	container_of(d, struct sdebug_host_info, dev)
272fd32119bSDouglas Gilbert 
27310bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
27410bde980SDouglas Gilbert 		      SDEB_DEFER_WQ = 2};
27510bde980SDouglas Gilbert 
276fd32119bSDouglas Gilbert struct sdebug_defer {
277fd32119bSDouglas Gilbert 	struct hrtimer hrt;
278fd32119bSDouglas Gilbert 	struct execute_work ew;
279c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
280c4837394SDouglas Gilbert 	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
281c4837394SDouglas Gilbert 	int issuing_cpu;
28210bde980SDouglas Gilbert 	bool init_hrt;
28310bde980SDouglas Gilbert 	bool init_wq;
28410bde980SDouglas Gilbert 	enum sdeb_defer_type defer_t;
285fd32119bSDouglas Gilbert };
286fd32119bSDouglas Gilbert 
287fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
288c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
289c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
290c4837394SDouglas Gilbert 	 */
291fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
292fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
293c4837394SDouglas Gilbert 	unsigned int inj_recovered:1;
294c4837394SDouglas Gilbert 	unsigned int inj_transport:1;
295c4837394SDouglas Gilbert 	unsigned int inj_dif:1;
296c4837394SDouglas Gilbert 	unsigned int inj_dix:1;
297c4837394SDouglas Gilbert 	unsigned int inj_short:1;
2987ee6d1b4SBart Van Assche 	unsigned int inj_host_busy:1;
299fd32119bSDouglas Gilbert };
300fd32119bSDouglas Gilbert 
301c4837394SDouglas Gilbert struct sdebug_queue {
302c4837394SDouglas Gilbert 	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
303c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
304c4837394SDouglas Gilbert 	spinlock_t qc_lock;
305c4837394SDouglas Gilbert 	atomic_t blocked;	/* to temporarily stop more being queued */
306fd32119bSDouglas Gilbert };
307fd32119bSDouglas Gilbert 
308c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
309c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
310c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
311c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
312c4837394SDouglas Gilbert 
313fd32119bSDouglas Gilbert struct opcode_info_t {
314b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
315b01f6f83SDouglas Gilbert 				/* for terminating element */
316fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
317fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
318fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
319fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
320fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
3219a051019SDouglas Gilbert 	u8 len_mask[16];	/* len_mask[0]-->cdb_len, then mask for cdb */
3229a051019SDouglas Gilbert 				/* 1 to min(cdb_len, 15); ignore cdb[15...] */
323fd32119bSDouglas Gilbert };
324fd32119bSDouglas Gilbert 
325fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
326c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
327c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
328c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
329c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
330c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
331c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
332c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
333c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
334c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
335c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
336c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
337c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
338c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
33946f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_IN_16 = 12,	/* add ...SERV_ACT_IN_12 if needed */
34046f64e70SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT_16 = 13,	/* add ...SERV_ACT_OUT_12 if needed */
341c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
342c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
343c2248fc9SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* 10 only */
344481b5e5cSDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,	/* READ(32), WRITE(32), WR_SCAT(32) */
345c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
346c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
347c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
348c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
349c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
350c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
351c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
352c2248fc9SDouglas Gilbert 	SDEB_I_XDWRITEREAD = 25,	/* 10 only */
353c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_BUFFER = 26,
354c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_SAME = 27,		/* 10, 16 */
35580c49563SDouglas Gilbert 	SDEB_I_SYNC_CACHE = 28,		/* 10, 16 */
356c2248fc9SDouglas Gilbert 	SDEB_I_COMP_WRITE = 29,
3579a051019SDouglas Gilbert 	SDEB_I_LAST_ELEMENT = 30,	/* keep this last (previous + 1) */
358c2248fc9SDouglas Gilbert };
359c2248fc9SDouglas Gilbert 
360c4837394SDouglas Gilbert 
361c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
362c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
363c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
364c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
365c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
366c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
367c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
368c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
369c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
370c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
371c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
372c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
373c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
374c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
375c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
376c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
377c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
378c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
379c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
380c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
381fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
382c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
383c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
384c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
385c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
386c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
387c2248fc9SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
38880c49563SDouglas Gilbert 	0, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
38946f64e70SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
390c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
391c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
392c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
39346f64e70SDouglas Gilbert 	SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
39446f64e70SDouglas Gilbert 	     0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
395c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
396c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
397c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
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 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
401c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
402c2248fc9SDouglas Gilbert };
403c2248fc9SDouglas Gilbert 
40480c49563SDouglas Gilbert /*
40580c49563SDouglas Gilbert  * The following "response" functions return the SCSI mid-level's 4 byte
40680c49563SDouglas Gilbert  * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
40780c49563SDouglas Gilbert  * command completion, they can mask their return value with
40880c49563SDouglas Gilbert  * SDEG_RES_IMMED_MASK .
40980c49563SDouglas Gilbert  */
41080c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000
41180c49563SDouglas Gilbert 
412c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
413c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
414c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
415c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
416c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
417c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
418c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
419c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
420c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
421481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
422c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
423c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
424c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
425c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
426c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
42738d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
42838d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
429c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
430c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
431c2248fc9SDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
43238d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
433acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
43480c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
435c2248fc9SDouglas Gilbert 
43646f64e70SDouglas Gilbert /*
43746f64e70SDouglas Gilbert  * The following are overflow arrays for cdbs that "hit" the same index in
43846f64e70SDouglas Gilbert  * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
43946f64e70SDouglas Gilbert  * should be placed in opcode_info_arr[], the others should be placed here.
44046f64e70SDouglas Gilbert  */
44146f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = {
442c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
443c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
444c2248fc9SDouglas Gilbert };
445c2248fc9SDouglas Gilbert 
44646f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = {
447c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
448c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
449c2248fc9SDouglas Gilbert };
450c2248fc9SDouglas Gilbert 
45146f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = {
45246f64e70SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
453b7e24581SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
454c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
45546f64e70SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
456c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
45746f64e70SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
458b7e24581SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
459c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
460c2248fc9SDouglas Gilbert };
461c2248fc9SDouglas Gilbert 
46246f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = {
46346f64e70SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
46446f64e70SDouglas Gilbert 	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
46546f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
46646f64e70SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
46746f64e70SDouglas Gilbert 	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
46846f64e70SDouglas Gilbert 		   0, 0, 0} },
46946f64e70SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
47046f64e70SDouglas Gilbert 	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
47146f64e70SDouglas Gilbert 		   0xbf, 0xc7, 0, 0, 0, 0} },
472c2248fc9SDouglas Gilbert };
473c2248fc9SDouglas Gilbert 
47446f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = {
475c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
476c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
47746f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
478c2248fc9SDouglas Gilbert };
479c2248fc9SDouglas Gilbert 
48046f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
48146f64e70SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
482b7e24581SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
483c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
484481b5e5cSDouglas Gilbert 	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
485481b5e5cSDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
486481b5e5cSDouglas Gilbert 		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */
487c2248fc9SDouglas Gilbert };
488c2248fc9SDouglas Gilbert 
48946f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
49038d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
491c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
49246f64e70SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
49338d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
494c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
49546f64e70SDouglas Gilbert 	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
496c2248fc9SDouglas Gilbert };
497c2248fc9SDouglas Gilbert 
49846f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = {
49946f64e70SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
500c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
50146f64e70SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
502c2248fc9SDouglas Gilbert };
503c2248fc9SDouglas Gilbert 
50446f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = {
505c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
506c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
507c2248fc9SDouglas Gilbert };
508c2248fc9SDouglas Gilbert 
50946f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = {
510c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
511c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
512c2248fc9SDouglas Gilbert };
513c2248fc9SDouglas Gilbert 
51480c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = {
5154f2c8bf6SDouglas Gilbert 	{0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
51680c49563SDouglas Gilbert 	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
51780c49563SDouglas Gilbert 	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
51880c49563SDouglas Gilbert };
51980c49563SDouglas Gilbert 
520c2248fc9SDouglas Gilbert 
521c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
522c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
523c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
524c2248fc9SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
525c2248fc9SDouglas Gilbert /* 0 */
52646f64e70SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
527c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
52846f64e70SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
529c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
530c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
531c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
53246f64e70SDouglas Gilbert 	     0, 0} },					/* REPORT LUNS */
533c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
534c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
535c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
536c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
53746f64e70SDouglas Gilbert /* 5 */
53846f64e70SDouglas Gilbert 	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
53946f64e70SDouglas Gilbert 	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
54046f64e70SDouglas Gilbert 		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
54146f64e70SDouglas Gilbert 	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
54246f64e70SDouglas Gilbert 	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
54346f64e70SDouglas Gilbert 		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
54446f64e70SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
545c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
546c2248fc9SDouglas Gilbert 	     0, 0, 0} },
54746f64e70SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
548c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
549c2248fc9SDouglas Gilbert 	     0, 0} },
55046f64e70SDouglas Gilbert 	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
55146f64e70SDouglas Gilbert 	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
55246f64e70SDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
553c2248fc9SDouglas Gilbert /* 10 */
55446f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
55546f64e70SDouglas Gilbert 	    resp_write_dt0, write_iarr,			/* WRITE(16) */
55646f64e70SDouglas Gilbert 		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55780c49563SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
5584f2c8bf6SDouglas Gilbert 	{0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
559c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
56046f64e70SDouglas Gilbert 	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
56146f64e70SDouglas Gilbert 	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
56246f64e70SDouglas Gilbert 		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
56346f64e70SDouglas Gilbert 		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
564481b5e5cSDouglas Gilbert 	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
565481b5e5cSDouglas Gilbert 	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
566481b5e5cSDouglas Gilbert 	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */
56746f64e70SDouglas Gilbert 	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
56846f64e70SDouglas Gilbert 	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
56946f64e70SDouglas Gilbert 		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
57046f64e70SDouglas Gilbert 				0xff, 0, 0xc7, 0, 0, 0, 0} },
57146f64e70SDouglas Gilbert /* 15 */
572c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
573c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
57446f64e70SDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, NULL, NULL, /* VERIFY(10) */
575f7f9f26bSDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
576f7f9f26bSDouglas Gilbert 	     0, 0, 0, 0, 0, 0} },
57746f64e70SDouglas Gilbert 	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
57846f64e70SDouglas Gilbert 	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
57946f64e70SDouglas Gilbert 	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
58046f64e70SDouglas Gilbert 	     0xff, 0xff} },
58146f64e70SDouglas Gilbert 	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
58246f64e70SDouglas Gilbert 	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
583c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
584c2248fc9SDouglas Gilbert 	     0} },
58546f64e70SDouglas Gilbert 	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
58646f64e70SDouglas Gilbert 	    NULL, release_iarr, /* RELEASE(10) <no response function> */
587c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
588c2248fc9SDouglas Gilbert 	     0} },
589c2248fc9SDouglas Gilbert /* 20 */
590f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
591f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
592c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
593c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
594c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
595c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
596c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
597c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
59846f64e70SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
599b7e24581SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
60046f64e70SDouglas Gilbert /* 25 */
60146f64e70SDouglas Gilbert 	{0, 0x53, 0, F_D_IN | F_D_OUT | FF_MEDIA_IO, resp_xdwriteread_10,
602b7e24581SDouglas Gilbert 	    NULL, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
60346f64e70SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },		/* XDWRITEREAD(10) */
604acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
605acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
606acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
60746f64e70SDouglas Gilbert 	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
60846f64e70SDouglas Gilbert 	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
60946f64e70SDouglas Gilbert 		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
61046f64e70SDouglas Gilbert 		 0, 0, 0, 0, 0} },
6114f2c8bf6SDouglas Gilbert 	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
61280c49563SDouglas Gilbert 	    resp_sync_cache, sync_cache_iarr,
613b7e24581SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
61480c49563SDouglas Gilbert 	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
61546f64e70SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
616c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
617b7e24581SDouglas Gilbert 	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
618c2248fc9SDouglas Gilbert 
619c2248fc9SDouglas Gilbert /* 30 */
620c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
621c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
622c2248fc9SDouglas Gilbert };
623c2248fc9SDouglas Gilbert 
624773642d9SDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;
625773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
6269b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN;
627c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
628773642d9SDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
629773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
630773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
631773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
632773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
633773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
634773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
635773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
636773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
637c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
638d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
639d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
640cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
641c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
642773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
643773642d9SDouglas Gilbert static int sdebug_no_uld;
644773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
645773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
646773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
647773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
648773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
64986e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
650b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
651773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
652773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
653773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
654773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
655773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
656773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
657773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
658773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
659773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
660773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
661773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
662773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
663773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
66409ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
665773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
666773642d9SDouglas Gilbert static bool sdebug_clustering;
667773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
668773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
669817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
670773642d9SDouglas Gilbert static bool sdebug_verbose;
671f46eb0e9SDouglas Gilbert static bool have_dif_prot;
6724f2c8bf6SDouglas Gilbert static bool write_since_sync;
673c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
6741da177e4SLinus Torvalds 
675c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
6761da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
6771da177e4SLinus Torvalds 
6781da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
6791da177e4SLinus Torvalds    may still need them */
6801da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
6811da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
6821da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
6831da177e4SLinus Torvalds 
6841da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
6851da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
6861da177e4SLinus Torvalds 
6871da177e4SLinus Torvalds static unsigned char *fake_storep;	/* ramdisk storage */
6886ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_storep;	/* protection info */
68944d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
6901da177e4SLinus Torvalds 
69144d92694SMartin K. Petersen static unsigned long map_size;
692cbf67842SDouglas Gilbert static int num_aborts;
693cbf67842SDouglas Gilbert static int num_dev_resets;
694cbf67842SDouglas Gilbert static int num_target_resets;
695cbf67842SDouglas Gilbert static int num_bus_resets;
696cbf67842SDouglas Gilbert static int num_host_resets;
697c6a44287SMartin K. Petersen static int dix_writes;
698c6a44287SMartin K. Petersen static int dix_reads;
699c6a44287SMartin K. Petersen static int dif_errors;
7001da177e4SLinus Torvalds 
701c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
702c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
703fd32119bSDouglas Gilbert 
7041da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
7051da177e4SLinus Torvalds 
706cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
707cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
7081da177e4SLinus Torvalds 
7091da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
7101da177e4SLinus Torvalds 
7111da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
7121da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
7131da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
7141da177e4SLinus Torvalds };
7151da177e4SLinus Torvalds 
7161da177e4SLinus Torvalds static const int check_condition_result =
7171da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
7181da177e4SLinus Torvalds 
719c6a44287SMartin K. Petersen static const int illegal_condition_result =
720c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
721c6a44287SMartin K. Petersen 
722cbf67842SDouglas Gilbert static const int device_qfull_result =
723cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
724cbf67842SDouglas Gilbert 
725fd32119bSDouglas Gilbert 
726760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
727760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
728760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
729760f3b03SDouglas Gilbert  */
730760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
731fd32119bSDouglas Gilbert {
732fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
733fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
734fd32119bSDouglas Gilbert }
735c65b1445SDouglas Gilbert 
73614faa944SAkinobu Mita static void *fake_store(unsigned long long lba)
73714faa944SAkinobu Mita {
73814faa944SAkinobu Mita 	lba = do_div(lba, sdebug_store_sectors);
73914faa944SAkinobu Mita 
740773642d9SDouglas Gilbert 	return fake_storep + lba * sdebug_sector_size;
74114faa944SAkinobu Mita }
74214faa944SAkinobu Mita 
7436ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_store(sector_t sector)
74414faa944SAkinobu Mita {
74549413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
74614faa944SAkinobu Mita 
74714faa944SAkinobu Mita 	return dif_storep + sector;
74814faa944SAkinobu Mita }
74914faa944SAkinobu Mita 
7508dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
7518dea0d02SFUJITA Tomonori {
7528dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
7538dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
7548dea0d02SFUJITA Tomonori 
7558dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
7568dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
7578dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
7588dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
759773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
760773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
7618dea0d02SFUJITA Tomonori 		else
762773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
763773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
764f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
7658dea0d02SFUJITA Tomonori 	}
7668dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
7678dea0d02SFUJITA Tomonori }
7688dea0d02SFUJITA Tomonori 
76922017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
77022017ed2SDouglas Gilbert 
77122017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
772fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
773fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
77422017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
77522017ed2SDouglas Gilbert {
77622017ed2SDouglas Gilbert 	unsigned char *sbuff;
77722017ed2SDouglas Gilbert 	u8 sks[4];
77822017ed2SDouglas Gilbert 	int sl, asc;
77922017ed2SDouglas Gilbert 
78022017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
78122017ed2SDouglas Gilbert 	if (!sbuff) {
78222017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
78322017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
78422017ed2SDouglas Gilbert 		return;
78522017ed2SDouglas Gilbert 	}
78622017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
78722017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
788773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
78922017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
79022017ed2SDouglas Gilbert 	sks[0] = 0x80;
79122017ed2SDouglas Gilbert 	if (c_d)
79222017ed2SDouglas Gilbert 		sks[0] |= 0x40;
79322017ed2SDouglas Gilbert 	if (in_bit >= 0) {
79422017ed2SDouglas Gilbert 		sks[0] |= 0x8;
79522017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
79622017ed2SDouglas Gilbert 	}
79722017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
798773642d9SDouglas Gilbert 	if (sdebug_dsense) {
79922017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
80022017ed2SDouglas Gilbert 		sbuff[7] = sl;
80122017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
80222017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
80322017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
80422017ed2SDouglas Gilbert 	} else
80522017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
806773642d9SDouglas Gilbert 	if (sdebug_verbose)
80722017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
80822017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
80922017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
81022017ed2SDouglas Gilbert }
81122017ed2SDouglas Gilbert 
812cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
8138dea0d02SFUJITA Tomonori {
8148dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
8158dea0d02SFUJITA Tomonori 
816cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
817cbf67842SDouglas Gilbert 	if (!sbuff) {
818cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
819cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
820cbf67842SDouglas Gilbert 		return;
821cbf67842SDouglas Gilbert 	}
822cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
8238dea0d02SFUJITA Tomonori 
824773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
8258dea0d02SFUJITA Tomonori 
826773642d9SDouglas Gilbert 	if (sdebug_verbose)
827cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
828cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
829cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
8308dea0d02SFUJITA Tomonori }
8311da177e4SLinus Torvalds 
832fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
83322017ed2SDouglas Gilbert {
83422017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
83522017ed2SDouglas Gilbert }
83622017ed2SDouglas Gilbert 
8371da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
8381da177e4SLinus Torvalds {
839773642d9SDouglas Gilbert 	if (sdebug_verbose) {
840cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
841cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
842cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
843cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
844cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
845cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
846cbf67842SDouglas Gilbert 				    __func__);
847cbf67842SDouglas Gilbert 		else
848cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
849cbf67842SDouglas Gilbert 				    __func__, cmd);
8501da177e4SLinus Torvalds 	}
8511da177e4SLinus Torvalds 	return -EINVAL;
8521da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
8531da177e4SLinus Torvalds }
8541da177e4SLinus Torvalds 
8559b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev)
8569b760fd8SDouglas Gilbert {
8579b760fd8SDouglas Gilbert 	switch (sdebug_cdb_len) {
8589b760fd8SDouglas Gilbert 	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
8599b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8609b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8619b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8629b760fd8SDouglas Gilbert 		break;
8639b760fd8SDouglas Gilbert 	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
8649b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8659b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8669b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8679b760fd8SDouglas Gilbert 		break;
8689b760fd8SDouglas Gilbert 	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
8699b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8709b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8719b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8729b760fd8SDouglas Gilbert 		break;
8739b760fd8SDouglas Gilbert 	case 16:
8749b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8759b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
8769b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8779b760fd8SDouglas Gilbert 		break;
8789b760fd8SDouglas Gilbert 	case 32: /* No knobs to suggest this so same as 16 for now */
8799b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = false;
8809b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = true;
8819b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = true;
8829b760fd8SDouglas Gilbert 		break;
8839b760fd8SDouglas Gilbert 	default:
8849b760fd8SDouglas Gilbert 		pr_warn("unexpected cdb_len=%d, force to 10\n",
8859b760fd8SDouglas Gilbert 			sdebug_cdb_len);
8869b760fd8SDouglas Gilbert 		sdev->use_10_for_rw = true;
8879b760fd8SDouglas Gilbert 		sdev->use_16_for_rw = false;
8889b760fd8SDouglas Gilbert 		sdev->use_10_for_ms = false;
8899b760fd8SDouglas Gilbert 		sdebug_cdb_len = 10;
8909b760fd8SDouglas Gilbert 		break;
8919b760fd8SDouglas Gilbert 	}
8929b760fd8SDouglas Gilbert }
8939b760fd8SDouglas Gilbert 
8949b760fd8SDouglas Gilbert static void all_config_cdb_len(void)
8959b760fd8SDouglas Gilbert {
8969b760fd8SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
8979b760fd8SDouglas Gilbert 	struct Scsi_Host *shost;
8989b760fd8SDouglas Gilbert 	struct scsi_device *sdev;
8999b760fd8SDouglas Gilbert 
9009b760fd8SDouglas Gilbert 	spin_lock(&sdebug_host_list_lock);
9019b760fd8SDouglas Gilbert 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
9029b760fd8SDouglas Gilbert 		shost = sdbg_host->shost;
9039b760fd8SDouglas Gilbert 		shost_for_each_device(sdev, shost) {
9049b760fd8SDouglas Gilbert 			config_cdb_len(sdev);
9059b760fd8SDouglas Gilbert 		}
9069b760fd8SDouglas Gilbert 	}
9079b760fd8SDouglas Gilbert 	spin_unlock(&sdebug_host_list_lock);
9089b760fd8SDouglas Gilbert }
9099b760fd8SDouglas Gilbert 
91019c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
91119c8ead7SEwan D. Milne {
91219c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
91319c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
91419c8ead7SEwan D. Milne 
91519c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
91619c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
91719c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
91819c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
91919c8ead7SEwan D. Milne 			    (devip->target == dp->target))
92019c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
92119c8ead7SEwan D. Milne 		}
92219c8ead7SEwan D. Milne 	}
92319c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
92419c8ead7SEwan D. Milne }
92519c8ead7SEwan D. Milne 
926f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
9271da177e4SLinus Torvalds {
928cbf67842SDouglas Gilbert 	int k;
929cbf67842SDouglas Gilbert 
930cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
931cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
932cbf67842SDouglas Gilbert 		const char *cp = NULL;
933cbf67842SDouglas Gilbert 
934cbf67842SDouglas Gilbert 		switch (k) {
935cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
936f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
937f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
938773642d9SDouglas Gilbert 			if (sdebug_verbose)
939cbf67842SDouglas Gilbert 				cp = "power on reset";
940cbf67842SDouglas Gilbert 			break;
941cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
942f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
943f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
944773642d9SDouglas Gilbert 			if (sdebug_verbose)
945cbf67842SDouglas Gilbert 				cp = "bus reset";
946cbf67842SDouglas Gilbert 			break;
947cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
948f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
949f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
950773642d9SDouglas Gilbert 			if (sdebug_verbose)
951cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
952cbf67842SDouglas Gilbert 			break;
9530d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
954f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
955f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
956773642d9SDouglas Gilbert 			if (sdebug_verbose)
9570d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
958f49accf1SEwan D. Milne 			break;
959acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
960f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
961b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
962b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
963773642d9SDouglas Gilbert 			if (sdebug_verbose)
964acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
965acafd0b9SEwan D. Milne 			break;
966acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
967f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
968acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
969acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
970773642d9SDouglas Gilbert 			if (sdebug_verbose)
971acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
972acafd0b9SEwan D. Milne 			break;
97319c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
97419c8ead7SEwan D. Milne 			/*
97519c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
97619c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
97719c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
97819c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
979773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
98019c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
98119c8ead7SEwan D. Milne 			 */
982773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
98319c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
984f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
98519c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
98619c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
987773642d9SDouglas Gilbert 			if (sdebug_verbose)
98819c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
98919c8ead7SEwan D. Milne 			break;
990cbf67842SDouglas Gilbert 		default:
991773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
992773642d9SDouglas Gilbert 			if (sdebug_verbose)
993cbf67842SDouglas Gilbert 				cp = "unknown";
994cbf67842SDouglas Gilbert 			break;
995cbf67842SDouglas Gilbert 		}
996cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
997773642d9SDouglas Gilbert 		if (sdebug_verbose)
998f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
999cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
1000cbf67842SDouglas Gilbert 				   my_name, cp);
10011da177e4SLinus Torvalds 		return check_condition_result;
10021da177e4SLinus Torvalds 	}
10031da177e4SLinus Torvalds 	return 0;
10041da177e4SLinus Torvalds }
10051da177e4SLinus Torvalds 
1006fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
10071da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
10081da177e4SLinus Torvalds 				int arr_len)
10091da177e4SLinus Torvalds {
101021a61829SFUJITA Tomonori 	int act_len;
1011072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
10121da177e4SLinus Torvalds 
1013072d0bb3SFUJITA Tomonori 	if (!sdb->length)
10141da177e4SLinus Torvalds 		return 0;
1015072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
1016773642d9SDouglas Gilbert 		return DID_ERROR << 16;
101721a61829SFUJITA Tomonori 
101821a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
101921a61829SFUJITA Tomonori 				      arr, arr_len);
102021a61829SFUJITA Tomonori 	sdb->resid = scsi_bufflen(scp) - act_len;
102121a61829SFUJITA Tomonori 
10221da177e4SLinus Torvalds 	return 0;
10231da177e4SLinus Torvalds }
10241da177e4SLinus Torvalds 
1025fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1026fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1027fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
1028fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
1029fb0cc8d1SDouglas Gilbert  */
1030fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1031fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
1032fb0cc8d1SDouglas Gilbert {
1033fb0cc8d1SDouglas Gilbert 	int act_len, n;
1034fb0cc8d1SDouglas Gilbert 	struct scsi_data_buffer *sdb = scsi_in(scp);
1035fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
1036fb0cc8d1SDouglas Gilbert 
1037fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
1038fb0cc8d1SDouglas Gilbert 		return 0;
1039fb0cc8d1SDouglas Gilbert 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
1040fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
1041fb0cc8d1SDouglas Gilbert 
1042fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1043fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
1044fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
1045fb0cc8d1SDouglas Gilbert 		 __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid);
1046fb0cc8d1SDouglas Gilbert 	n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
1047fb0cc8d1SDouglas Gilbert 	sdb->resid = min(sdb->resid, n);
1048fb0cc8d1SDouglas Gilbert 	return 0;
1049fb0cc8d1SDouglas Gilbert }
1050fb0cc8d1SDouglas Gilbert 
1051fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1052fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
1053fb0cc8d1SDouglas Gilbert  */
10541da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
105521a61829SFUJITA Tomonori 			       int arr_len)
10561da177e4SLinus Torvalds {
105721a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
10581da177e4SLinus Torvalds 		return 0;
1059072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
10601da177e4SLinus Torvalds 		return -1;
106121a61829SFUJITA Tomonori 
106221a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
10631da177e4SLinus Torvalds }
10641da177e4SLinus Torvalds 
10651da177e4SLinus Torvalds 
1066e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
1067e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
10689b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
10691b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
10701b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
10711b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
10721b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
10731da177e4SLinus Torvalds 
1074cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
1075760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
10765a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
107709ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
1078bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
10791da177e4SLinus Torvalds {
1080c65b1445SDouglas Gilbert 	int num, port_a;
1081c65b1445SDouglas Gilbert 	char b[32];
10821da177e4SLinus Torvalds 
1083c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
10841da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
10851da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
10861da177e4SLinus Torvalds 	arr[1] = 0x1;
10871da177e4SLinus Torvalds 	arr[2] = 0x0;
1088e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1089e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
10901da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
10911da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
10921da177e4SLinus Torvalds 	arr[3] = num;
10931da177e4SLinus Torvalds 	num += 4;
1094c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
109509ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
109609ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
109709ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
109809ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
109909ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
110009ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
110109ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
110209ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
110309ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
110409ba24c1SDouglas Gilbert 			num += 16;
110509ba24c1SDouglas Gilbert 		} else {
11061b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
1107c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
1108c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
1109c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1110c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
11111b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1112773642d9SDouglas Gilbert 			num += 8;
111309ba24c1SDouglas Gilbert 		}
1114c65b1445SDouglas Gilbert 		/* Target relative port number */
1115c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1116c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1117c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1118c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1119c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1120c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1121c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1122c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1123c65b1445SDouglas Gilbert 	}
11241b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1125c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1126c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1127c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1128c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
11291b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1130773642d9SDouglas Gilbert 	num += 8;
11311b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
11325a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
11335a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
11345a09e398SHannes Reinecke 	arr[num++] = 0x0;
11355a09e398SHannes Reinecke 	arr[num++] = 0x4;
11365a09e398SHannes Reinecke 	arr[num++] = 0;
11375a09e398SHannes Reinecke 	arr[num++] = 0;
1138773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1139773642d9SDouglas Gilbert 	num += 2;
11401b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1141c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1142c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1143c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1144c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
11451b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1146773642d9SDouglas Gilbert 	num += 8;
1147c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1148c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1149c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1150c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1151c65b1445SDouglas Gilbert 	arr[num++] = 24;
11521b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1153c65b1445SDouglas Gilbert 	num += 12;
1154c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1155c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1156c65b1445SDouglas Gilbert 	num += 8;
1157c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1158c65b1445SDouglas Gilbert 	num += 4;
1159c65b1445SDouglas Gilbert 	return num;
1160c65b1445SDouglas Gilbert }
1161c65b1445SDouglas Gilbert 
1162c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1163c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1164c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1165c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1166c65b1445SDouglas Gilbert };
1167c65b1445SDouglas Gilbert 
1168cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1169760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1170c65b1445SDouglas Gilbert {
1171c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1172c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1173c65b1445SDouglas Gilbert }
1174c65b1445SDouglas Gilbert 
1175cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1176760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1177c65b1445SDouglas Gilbert {
1178c65b1445SDouglas Gilbert 	int num = 0;
1179c65b1445SDouglas Gilbert 	const char *na1 = "https://www.kernel.org/config";
1180c65b1445SDouglas Gilbert 	const char *na2 = "http://www.kernel.org/log";
1181c65b1445SDouglas Gilbert 	int plen, olen;
1182c65b1445SDouglas Gilbert 
1183c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1184c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1185c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1186c65b1445SDouglas Gilbert 	olen = strlen(na1);
1187c65b1445SDouglas Gilbert 	plen = olen + 1;
1188c65b1445SDouglas Gilbert 	if (plen % 4)
1189c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1190c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1191c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1192c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1193c65b1445SDouglas Gilbert 	num += plen;
1194c65b1445SDouglas Gilbert 
1195c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1196c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1197c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1198c65b1445SDouglas Gilbert 	olen = strlen(na2);
1199c65b1445SDouglas Gilbert 	plen = olen + 1;
1200c65b1445SDouglas Gilbert 	if (plen % 4)
1201c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1202c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1203c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1204c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1205c65b1445SDouglas Gilbert 	num += plen;
1206c65b1445SDouglas Gilbert 
1207c65b1445SDouglas Gilbert 	return num;
1208c65b1445SDouglas Gilbert }
1209c65b1445SDouglas Gilbert 
1210c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1211760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1212c65b1445SDouglas Gilbert {
1213c65b1445SDouglas Gilbert 	int num = 0;
1214c65b1445SDouglas Gilbert 	int port_a, port_b;
1215c65b1445SDouglas Gilbert 
1216c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1217c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1218c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1219c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1220c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1221c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1222c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1223c65b1445SDouglas Gilbert 	num += 6;
1224c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1225c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1226c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1227c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1228c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1229c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1230c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
12311b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1232773642d9SDouglas Gilbert 	num += 8;
1233c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1234c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1235c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1236c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1237c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1238c65b1445SDouglas Gilbert 	num += 6;
1239c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1240c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1241c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1242c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1243c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1244c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1245c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
12461b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1247773642d9SDouglas Gilbert 	num += 8;
1248c65b1445SDouglas Gilbert 
1249c65b1445SDouglas Gilbert 	return num;
1250c65b1445SDouglas Gilbert }
1251c65b1445SDouglas Gilbert 
1252c65b1445SDouglas Gilbert 
1253c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1254c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1255c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1256c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1257c65b1445SDouglas Gilbert '1','2','3','4',
1258c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1259c65b1445SDouglas Gilbert 0xec,0,0,0,
1260c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1261c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1262c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1263c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1264c65b1445SDouglas Gilbert 0x53,0x41,
1265c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1266c65b1445SDouglas Gilbert 0x20,0x20,
1267c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1268c65b1445SDouglas Gilbert 0x10,0x80,
1269c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1270c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1271c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1272c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1273c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1274c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1275c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1276c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1277c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1278c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1279c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1280c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1281c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1282c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0,
1292c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1293c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1294c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1295c65b1445SDouglas Gilbert };
1296c65b1445SDouglas Gilbert 
1297cbf67842SDouglas Gilbert /* ATA Information VPD page */
1298760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1299c65b1445SDouglas Gilbert {
1300c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1301c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1302c65b1445SDouglas Gilbert }
1303c65b1445SDouglas Gilbert 
1304c65b1445SDouglas Gilbert 
1305c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
13061e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
13071e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
13081e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
13091e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1310c65b1445SDouglas Gilbert };
1311c65b1445SDouglas Gilbert 
1312cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1313760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1314c65b1445SDouglas Gilbert {
1315ea61fca5SMartin K. Petersen 	unsigned int gran;
1316ea61fca5SMartin K. Petersen 
1317c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1318e308b3d1SMartin K. Petersen 
1319e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
132086e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
132186e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
132286e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
132386e6828aSLukas Herbolt 	else
1324773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1325773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1326e308b3d1SMartin K. Petersen 
1327e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1328773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1329773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
133044d92694SMartin K. Petersen 
1331e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1332773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1333e308b3d1SMartin K. Petersen 
1334773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1335e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1336773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1337e308b3d1SMartin K. Petersen 
1338e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1339773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
134044d92694SMartin K. Petersen 	}
134144d92694SMartin K. Petersen 
1342e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1343773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1344773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
134544d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
134644d92694SMartin K. Petersen 	}
134744d92694SMartin K. Petersen 
1348e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1349773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
13506014759cSMartin K. Petersen 
13515b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1352773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
13535b94e232SMartin K. Petersen 
13545b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
135544d92694SMartin K. Petersen 
1356c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
13571da177e4SLinus Torvalds }
13581da177e4SLinus Torvalds 
13591e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
1360760f3b03SDouglas Gilbert static int inquiry_vpd_b1(unsigned char *arr)
1361eac6e8e4SMatthew Wilcox {
1362eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1363eac6e8e4SMatthew Wilcox 	arr[0] = 0;
13641e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
13651e49f785SDouglas Gilbert 	arr[2] = 0;
13661e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
1367eac6e8e4SMatthew Wilcox 
1368eac6e8e4SMatthew Wilcox 	return 0x3c;
1369eac6e8e4SMatthew Wilcox }
13701da177e4SLinus Torvalds 
1371760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1372760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
13736014759cSMartin K. Petersen {
13743f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
13756014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1376773642d9SDouglas Gilbert 	if (sdebug_lbpu)
13776014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1378773642d9SDouglas Gilbert 	if (sdebug_lbpws)
13796014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1380773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
13815b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1382760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1383760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1384760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1385760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1386760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
13873f0bc3b3SMartin K. Petersen 	return 0x4;
13886014759cSMartin K. Petersen }
13896014759cSMartin K. Petersen 
13901da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1391c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
13921da177e4SLinus Torvalds 
1393c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
13941da177e4SLinus Torvalds {
13951da177e4SLinus Torvalds 	unsigned char pq_pdt;
13965a09e398SHannes Reinecke 	unsigned char *arr;
139701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
13985a09e398SHannes Reinecke 	int alloc_len, n, ret;
1399760f3b03SDouglas Gilbert 	bool have_wlun, is_disk;
14001da177e4SLinus Torvalds 
1401773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
14026f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
14036f3cbf55SDouglas Gilbert 	if (! arr)
14046f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1405760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
1406b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1407c2248fc9SDouglas Gilbert 	if (have_wlun)
1408b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1409b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1410b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1411c65b1445SDouglas Gilbert 	else
1412773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
14131da177e4SLinus Torvalds 	arr[0] = pq_pdt;
14141da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
141522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
14165a09e398SHannes Reinecke 		kfree(arr);
14171da177e4SLinus Torvalds 		return check_condition_result;
14181da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
14195a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1420c65b1445SDouglas Gilbert 		char lu_id_str[6];
1421c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
14221da177e4SLinus Torvalds 
14235a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
14245a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1425b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
142623183910SDouglas Gilbert 			host_no = 0;
1427c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1428c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1429c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1430c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1431c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
14321da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1433c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1434c65b1445SDouglas Gilbert 			n = 4;
1435c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1436c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1437c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1438c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1439c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1440c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1441c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1442c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1443760f3b03SDouglas Gilbert 			if (is_disk) {	  /* SBC only */
1444c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1445760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1446760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1447760f3b03SDouglas Gilbert 				arr[n++] = 0xb2;  /* Logical Block Prov */
1448760f3b03SDouglas Gilbert 			}
1449c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
14501da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1451c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
14521da177e4SLinus Torvalds 			arr[3] = len;
1453c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
14541da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1455c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1456760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
14575a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
145809ba24c1SDouglas Gilbert 						lu_id_str, len,
145909ba24c1SDouglas Gilbert 						&devip->lu_name);
1460c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1461c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1462760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1463c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1464c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1465760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1466c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1467c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1468c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
14698475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1470c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1471760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1472c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1473c6a44287SMartin K. Petersen 			else
1474c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1475c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1476c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1477c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1478c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1479c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1480c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1481c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1482c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1483c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1484c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1485760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1486760f3b03SDouglas Gilbert 		} else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
1487c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1488760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1489773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1490760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
1491c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1492760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1493760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
1494eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
1495760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b1(&arr[4]);
1496760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
14976014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1498760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
14991da177e4SLinus Torvalds 		} else {
150022017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
15015a09e398SHannes Reinecke 			kfree(arr);
15021da177e4SLinus Torvalds 			return check_condition_result;
15031da177e4SLinus Torvalds 		}
1504773642d9SDouglas Gilbert 		len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
15055a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1506c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
15075a09e398SHannes Reinecke 		kfree(arr);
15085a09e398SHannes Reinecke 		return ret;
15091da177e4SLinus Torvalds 	}
15101da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1511773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1512773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
15131da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
15141da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1515f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1516b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
151770bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1518c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
15191da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1520c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1521e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1522e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1523e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
15249b760fd8SDouglas Gilbert 	/* Use Vendor Specific area to place driver date in ASCII hex */
15259b760fd8SDouglas Gilbert 	memcpy(&arr[36], sdebug_version_date, 8);
15261da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1527760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1528760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1529c65b1445SDouglas Gilbert 	n = 62;
1530760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1531760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1532760f3b03SDouglas Gilbert 		n += 2;
1533760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1534760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1535760f3b03SDouglas Gilbert 		n += 2;
15361da177e4SLinus Torvalds 	}
1537760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
15385a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
15391da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
15405a09e398SHannes Reinecke 	kfree(arr);
15415a09e398SHannes Reinecke 	return ret;
15421da177e4SLinus Torvalds }
15431da177e4SLinus Torvalds 
1544fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1545fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1546fd32119bSDouglas Gilbert 
15471da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp,
15481da177e4SLinus Torvalds 			 struct sdebug_dev_info *devip)
15491da177e4SLinus Torvalds {
15501da177e4SLinus Torvalds 	unsigned char *sbuff;
155101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1552cbf67842SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
15532492fc09STomas Winkler 	bool dsense;
15541da177e4SLinus Torvalds 	int len = 18;
15551da177e4SLinus Torvalds 
1556c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1557c2248fc9SDouglas Gilbert 	dsense = !!(cmd[1] & 1);
1558cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
1559c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1560c2248fc9SDouglas Gilbert 		if (dsense) {
1561c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1562c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1563c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
1564c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
1565c2248fc9SDouglas Gilbert 			len = 8;
1566c65b1445SDouglas Gilbert 		} else {
1567c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1568c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1569c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1570c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
1571c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
1572c65b1445SDouglas Gilbert 		}
1573c65b1445SDouglas Gilbert 	} else {
1574cbf67842SDouglas Gilbert 		memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
1575773642d9SDouglas Gilbert 		if (arr[0] >= 0x70 && dsense == sdebug_dsense)
1576c2248fc9SDouglas Gilbert 			;	/* have sense and formats match */
1577c2248fc9SDouglas Gilbert 		else if (arr[0] <= 0x70) {
1578c2248fc9SDouglas Gilbert 			if (dsense) {
1579c2248fc9SDouglas Gilbert 				memset(arr, 0, 8);
1580c2248fc9SDouglas Gilbert 				arr[0] = 0x72;
1581c2248fc9SDouglas Gilbert 				len = 8;
1582c2248fc9SDouglas Gilbert 			} else {
1583c2248fc9SDouglas Gilbert 				memset(arr, 0, 18);
1584c2248fc9SDouglas Gilbert 				arr[0] = 0x70;
1585c2248fc9SDouglas Gilbert 				arr[7] = 0xa;
1586c2248fc9SDouglas Gilbert 			}
1587c2248fc9SDouglas Gilbert 		} else if (dsense) {
1588c2248fc9SDouglas Gilbert 			memset(arr, 0, 8);
15891da177e4SLinus Torvalds 			arr[0] = 0x72;
15901da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
15911da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
15921da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
15931da177e4SLinus Torvalds 			len = 8;
1594c2248fc9SDouglas Gilbert 		} else {
1595c2248fc9SDouglas Gilbert 			memset(arr, 0, 18);
1596c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1597c2248fc9SDouglas Gilbert 			arr[2] = sbuff[1];
1598c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1599c2248fc9SDouglas Gilbert 			arr[12] = sbuff[1];
1600c2248fc9SDouglas Gilbert 			arr[13] = sbuff[3];
1601c65b1445SDouglas Gilbert 		}
1602c2248fc9SDouglas Gilbert 
1603c65b1445SDouglas Gilbert 	}
1604cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
16051da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
16061da177e4SLinus Torvalds }
16071da177e4SLinus Torvalds 
1608c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp,
1609c65b1445SDouglas Gilbert 			   struct sdebug_dev_info *devip)
1610c65b1445SDouglas Gilbert {
161101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1612c4837394SDouglas Gilbert 	int power_cond, stop;
16134f2c8bf6SDouglas Gilbert 	bool changing;
1614c65b1445SDouglas Gilbert 
1615c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1616c65b1445SDouglas Gilbert 	if (power_cond) {
161722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1618c65b1445SDouglas Gilbert 		return check_condition_result;
1619c65b1445SDouglas Gilbert 	}
1620c4837394SDouglas Gilbert 	stop = !(cmd[4] & 1);
16214f2c8bf6SDouglas Gilbert 	changing = atomic_read(&devip->stopped) == !stop;
1622c4837394SDouglas Gilbert 	atomic_xchg(&devip->stopped, stop);
16234f2c8bf6SDouglas Gilbert 	if (!changing || cmd[1] & 0x1)  /* state unchanged or IMMED set */
16244f2c8bf6SDouglas Gilbert 		return SDEG_RES_IMMED_MASK;
16254f2c8bf6SDouglas Gilbert 	else
16264f2c8bf6SDouglas Gilbert 		return 0;
1627c65b1445SDouglas Gilbert }
1628c65b1445SDouglas Gilbert 
162928898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
163028898873SFUJITA Tomonori {
1631773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1632773642d9SDouglas Gilbert 
1633773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1634773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1635773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
163628898873SFUJITA Tomonori 	else
163728898873SFUJITA Tomonori 		return sdebug_store_sectors;
163828898873SFUJITA Tomonori }
163928898873SFUJITA Tomonori 
16401da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
16411da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp,
16421da177e4SLinus Torvalds 			struct sdebug_dev_info *devip)
16431da177e4SLinus Torvalds {
16441da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1645c65b1445SDouglas Gilbert 	unsigned int capac;
16461da177e4SLinus Torvalds 
1647c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
164828898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
16491da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1650c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1651c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1652773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1653773642d9SDouglas Gilbert 	} else
1654773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1655773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
16561da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
16571da177e4SLinus Torvalds }
16581da177e4SLinus Torvalds 
1659c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1660c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp,
1661c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
1662c65b1445SDouglas Gilbert {
166301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1664c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1665773642d9SDouglas Gilbert 	int alloc_len;
1666c65b1445SDouglas Gilbert 
1667773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1668c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
166928898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1670c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1671773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1672773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1673773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1674773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
167544d92694SMartin K. Petersen 
1676be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
16775b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1678760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1679760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1680760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1681760f3b03SDouglas Gilbert 		 */
1682760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1683760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1684be1dd78dSEric Sandeen 	}
168544d92694SMartin K. Petersen 
1686773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1687c6a44287SMartin K. Petersen 
1688760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1689773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1690c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1691c6a44287SMartin K. Petersen 	}
1692c6a44287SMartin K. Petersen 
1693c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1694c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1695c65b1445SDouglas Gilbert }
1696c65b1445SDouglas Gilbert 
16975a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
16985a09e398SHannes Reinecke 
16995a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp,
17005a09e398SHannes Reinecke 			      struct sdebug_dev_info *devip)
17015a09e398SHannes Reinecke {
170201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
17035a09e398SHannes Reinecke 	unsigned char *arr;
17045a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
17055a09e398SHannes Reinecke 	int n, ret, alen, rlen;
17065a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
17075a09e398SHannes Reinecke 
1708773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
17096f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
17106f3cbf55SDouglas Gilbert 	if (! arr)
17116f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
17125a09e398SHannes Reinecke 	/*
17135a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
17145a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
17155a09e398SHannes Reinecke 	 * So we create two port groups with one port each
17165a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
17175a09e398SHannes Reinecke 	 */
17185a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
17195a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
17205a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
17215a09e398SHannes Reinecke 			(devip->channel & 0x7f);
17225a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
17235a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
17245a09e398SHannes Reinecke 
17255a09e398SHannes Reinecke 	/*
17265a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
17275a09e398SHannes Reinecke 	 */
17285a09e398SHannes Reinecke 	n = 4;
1729b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
17305a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
17315a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
17325a09e398SHannes Reinecke 	} else {
17335a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1734773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
17355a09e398SHannes Reinecke 	}
1736773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1737773642d9SDouglas Gilbert 	n += 2;
17385a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17395a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
17405a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
17415a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
17425a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17435a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1744773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1745773642d9SDouglas Gilbert 	n += 2;
17465a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
17475a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1748773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1749773642d9SDouglas Gilbert 	n += 2;
17505a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17515a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
17525a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
17535a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
17545a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
17555a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1756773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1757773642d9SDouglas Gilbert 	n += 2;
17585a09e398SHannes Reinecke 
17595a09e398SHannes Reinecke 	rlen = n - 4;
1760773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
17615a09e398SHannes Reinecke 
17625a09e398SHannes Reinecke 	/*
17635a09e398SHannes Reinecke 	 * Return the smallest value of either
17645a09e398SHannes Reinecke 	 * - The allocated length
17655a09e398SHannes Reinecke 	 * - The constructed command length
17665a09e398SHannes Reinecke 	 * - The maximum array size
17675a09e398SHannes Reinecke 	 */
17685a09e398SHannes Reinecke 	rlen = min(alen,n);
17695a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
17705a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
17715a09e398SHannes Reinecke 	kfree(arr);
17725a09e398SHannes Reinecke 	return ret;
17735a09e398SHannes Reinecke }
17745a09e398SHannes Reinecke 
1775fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1776fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
177738d5c833SDouglas Gilbert {
177838d5c833SDouglas Gilbert 	bool rctd;
177938d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
178038d5c833SDouglas Gilbert 	u16 req_sa, u;
178138d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
178238d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
178338d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
178438d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
178538d5c833SDouglas Gilbert 	u8 *arr;
178638d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
178738d5c833SDouglas Gilbert 
178838d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
178938d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
179038d5c833SDouglas Gilbert 	req_opcode = cmd[3];
179138d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
179238d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
17936d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
179438d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
179538d5c833SDouglas Gilbert 		return check_condition_result;
179638d5c833SDouglas Gilbert 	}
179738d5c833SDouglas Gilbert 	if (alloc_len > 8192)
179838d5c833SDouglas Gilbert 		a_len = 8192;
179938d5c833SDouglas Gilbert 	else
180038d5c833SDouglas Gilbert 		a_len = alloc_len;
180199531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
180238d5c833SDouglas Gilbert 	if (NULL == arr) {
180338d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
180438d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
180538d5c833SDouglas Gilbert 		return check_condition_result;
180638d5c833SDouglas Gilbert 	}
180738d5c833SDouglas Gilbert 	switch (reporting_opts) {
180838d5c833SDouglas Gilbert 	case 0:	/* all commands */
180938d5c833SDouglas Gilbert 		/* count number of commands */
181038d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
181138d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
181238d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
181338d5c833SDouglas Gilbert 				continue;
181438d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
181538d5c833SDouglas Gilbert 		}
181638d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
181738d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
181838d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
181938d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
182038d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
182138d5c833SDouglas Gilbert 				continue;
182238d5c833SDouglas Gilbert 			na = oip->num_attached;
182338d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
182438d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
182538d5c833SDouglas Gilbert 			if (rctd)
182638d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
182738d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
182838d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
182938d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
183038d5c833SDouglas Gilbert 			if (rctd)
183138d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
183238d5c833SDouglas Gilbert 			r_oip = oip;
183338d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
183438d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
183538d5c833SDouglas Gilbert 					continue;
183638d5c833SDouglas Gilbert 				offset += bump;
183738d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
183838d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
183938d5c833SDouglas Gilbert 				if (rctd)
184038d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
184138d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
184238d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
184338d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
184438d5c833SDouglas Gilbert 						   arr + offset + 6);
184538d5c833SDouglas Gilbert 				if (rctd)
184638d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
184738d5c833SDouglas Gilbert 							   arr + offset + 8);
184838d5c833SDouglas Gilbert 			}
184938d5c833SDouglas Gilbert 			oip = r_oip;
185038d5c833SDouglas Gilbert 			offset += bump;
185138d5c833SDouglas Gilbert 		}
185238d5c833SDouglas Gilbert 		break;
185338d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
185438d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
185538d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
185638d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
185738d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
185838d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
185938d5c833SDouglas Gilbert 			supp = 1;
186038d5c833SDouglas Gilbert 			offset = 4;
186138d5c833SDouglas Gilbert 		} else {
186238d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
186338d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
186438d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
186538d5c833SDouglas Gilbert 							     2, 2);
186638d5c833SDouglas Gilbert 					kfree(arr);
186738d5c833SDouglas Gilbert 					return check_condition_result;
186838d5c833SDouglas Gilbert 				}
186938d5c833SDouglas Gilbert 				req_sa = 0;
187038d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
187138d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
187238d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
187338d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
187438d5c833SDouglas Gilbert 				return check_condition_result;
187538d5c833SDouglas Gilbert 			}
187638d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
187738d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
187838d5c833SDouglas Gilbert 				supp = 3;
187938d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
188038d5c833SDouglas Gilbert 				na = oip->num_attached;
188138d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
188238d5c833SDouglas Gilbert 				     ++k, ++oip) {
188338d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
188438d5c833SDouglas Gilbert 						break;
188538d5c833SDouglas Gilbert 				}
188638d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
188738d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
188838d5c833SDouglas Gilbert 				na = oip->num_attached;
188938d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
189038d5c833SDouglas Gilbert 				     ++k, ++oip) {
189138d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
189238d5c833SDouglas Gilbert 						break;
189338d5c833SDouglas Gilbert 				}
189438d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
189538d5c833SDouglas Gilbert 			} else
189638d5c833SDouglas Gilbert 				supp = 3;
189738d5c833SDouglas Gilbert 			if (3 == supp) {
189838d5c833SDouglas Gilbert 				u = oip->len_mask[0];
189938d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
190038d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
190138d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
190238d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
190338d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
190438d5c833SDouglas Gilbert 				offset = 4 + u;
190538d5c833SDouglas Gilbert 			} else
190638d5c833SDouglas Gilbert 				offset = 4;
190738d5c833SDouglas Gilbert 		}
190838d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
190938d5c833SDouglas Gilbert 		if (rctd) {
191038d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
191138d5c833SDouglas Gilbert 			offset += 12;
191238d5c833SDouglas Gilbert 		}
191338d5c833SDouglas Gilbert 		break;
191438d5c833SDouglas Gilbert 	default:
191538d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
191638d5c833SDouglas Gilbert 		kfree(arr);
191738d5c833SDouglas Gilbert 		return check_condition_result;
191838d5c833SDouglas Gilbert 	}
191938d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
192038d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
192138d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
192238d5c833SDouglas Gilbert 	kfree(arr);
192338d5c833SDouglas Gilbert 	return errsts;
192438d5c833SDouglas Gilbert }
192538d5c833SDouglas Gilbert 
1926fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1927fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
192838d5c833SDouglas Gilbert {
192938d5c833SDouglas Gilbert 	bool repd;
193038d5c833SDouglas Gilbert 	u32 alloc_len, len;
193138d5c833SDouglas Gilbert 	u8 arr[16];
193238d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
193338d5c833SDouglas Gilbert 
193438d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
193538d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
193638d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
193738d5c833SDouglas Gilbert 	if (alloc_len < 4) {
193838d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
193938d5c833SDouglas Gilbert 		return check_condition_result;
194038d5c833SDouglas Gilbert 	}
194138d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
194238d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
194338d5c833SDouglas Gilbert 	if (repd) {
194438d5c833SDouglas Gilbert 		arr[3] = 0xc;
194538d5c833SDouglas Gilbert 		len = 16;
194638d5c833SDouglas Gilbert 	} else
194738d5c833SDouglas Gilbert 		len = 4;
194838d5c833SDouglas Gilbert 
194938d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
195038d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
195138d5c833SDouglas Gilbert }
195238d5c833SDouglas Gilbert 
19531da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
19541da177e4SLinus Torvalds 
19551da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
19561da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
19571da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
19581da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
19591da177e4SLinus Torvalds 
19601da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
19611da177e4SLinus Torvalds 	if (1 == pcontrol)
19621da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
19631da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
19641da177e4SLinus Torvalds }
19651da177e4SLinus Torvalds 
19661da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
19671da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
19681da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
19691da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
19701da177e4SLinus Torvalds 
19711da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
19721da177e4SLinus Torvalds 	if (1 == pcontrol)
19731da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
19741da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
19751da177e4SLinus Torvalds }
19761da177e4SLinus Torvalds 
19771da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target)
19781da177e4SLinus Torvalds {       /* Format device page for mode_sense */
19791da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
19801da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
19811da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
19821da177e4SLinus Torvalds 
19831da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
1984773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
1985773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
1986773642d9SDouglas Gilbert 	if (sdebug_removable)
19871da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
19881da177e4SLinus Torvalds 	if (1 == pcontrol)
19891da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
19901da177e4SLinus Torvalds 	return sizeof(format_pg);
19911da177e4SLinus Torvalds }
19921da177e4SLinus Torvalds 
1993fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1994fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1995fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
1996fd32119bSDouglas Gilbert 
19971da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
19981da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
1999cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2000cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2001cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
20021da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
20031da177e4SLinus Torvalds 
2004773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
2005cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
20061da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
20071da177e4SLinus Torvalds 	if (1 == pcontrol)
2008cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2009cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
2010cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
20111da177e4SLinus Torvalds 	return sizeof(caching_pg);
20121da177e4SLinus Torvalds }
20131da177e4SLinus Torvalds 
2014fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2015fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
2016fd32119bSDouglas Gilbert 
20171da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
20181da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
2019c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
2020c65b1445SDouglas Gilbert 					0, 0, 0, 0};
2021c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
20221da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
20231da177e4SLinus Torvalds 
2024773642d9SDouglas Gilbert 	if (sdebug_dsense)
20251da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
2026c65b1445SDouglas Gilbert 	else
2027c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
2028c6a44287SMartin K. Petersen 
2029773642d9SDouglas Gilbert 	if (sdebug_ato)
2030c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2031c6a44287SMartin K. Petersen 
20321da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
20331da177e4SLinus Torvalds 	if (1 == pcontrol)
2034c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2035c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2036c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
20371da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
20381da177e4SLinus Torvalds }
20391da177e4SLinus Torvalds 
2040c65b1445SDouglas Gilbert 
20411da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
20421da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
2043c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
20441da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
2045c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2046c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
2047c65b1445SDouglas Gilbert 
20481da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
20491da177e4SLinus Torvalds 	if (1 == pcontrol)
2050c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2051c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
2052c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
20531da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
20541da177e4SLinus Torvalds }
20551da177e4SLinus Torvalds 
2056c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
2057c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
2058c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2059c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2060c65b1445SDouglas Gilbert 
2061c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2062c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2063c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2064c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
2065c65b1445SDouglas Gilbert }
2066c65b1445SDouglas Gilbert 
2067c65b1445SDouglas Gilbert 
2068c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
2069c65b1445SDouglas Gilbert 			      int target_dev_id)
2070c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
2071c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2072c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
2073773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2074773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2075c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
2076c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2077c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2078c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
2079773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2080773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
2081c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
2082c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
2083c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2084c65b1445SDouglas Gilbert 		};
2085c65b1445SDouglas Gilbert 	int port_a, port_b;
2086c65b1445SDouglas Gilbert 
20871b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
20881b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
20891b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
20901b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
2091c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
2092c65b1445SDouglas Gilbert 	port_b = port_a + 1;
2093c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
2094773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
2095773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
2096c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2097c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2098c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
2099c65b1445SDouglas Gilbert }
2100c65b1445SDouglas Gilbert 
2101c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
2102c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
2103c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2104c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
2105c65b1445SDouglas Gilbert 		};
2106c65b1445SDouglas Gilbert 
2107c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2108c65b1445SDouglas Gilbert 	if (1 == pcontrol)
2109c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2110c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
2111c65b1445SDouglas Gilbert }
2112c65b1445SDouglas Gilbert 
21131da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
21141da177e4SLinus Torvalds 
2115fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
2116fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
21171da177e4SLinus Torvalds {
211823183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
21191da177e4SLinus Torvalds 	unsigned char dev_spec;
2120760f3b03SDouglas Gilbert 	int alloc_len, offset, len, target_dev_id;
2121c2248fc9SDouglas Gilbert 	int target = scp->device->id;
21221da177e4SLinus Torvalds 	unsigned char *ap;
21231da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
212401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2125760f3b03SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, bad_pcode;
21261da177e4SLinus Torvalds 
2127760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
21281da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
21291da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
21301da177e4SLinus Torvalds 	subpcode = cmd[3];
21311da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2132760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2133760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
2134760f3b03SDouglas Gilbert 	if (is_disk && !dbd)
213523183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
213623183910SDouglas Gilbert 	else
213723183910SDouglas Gilbert 		bd_len = 0;
2138773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
21391da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
21401da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2141cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
21421da177e4SLinus Torvalds 		return check_condition_result;
21431da177e4SLinus Torvalds 	}
2144c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2145c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2146b01f6f83SDouglas Gilbert 	/* for disks set DPOFUA bit and clear write protect (WP) bit */
2147760f3b03SDouglas Gilbert 	if (is_disk)
2148b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
214923183910SDouglas Gilbert 	else
215023183910SDouglas Gilbert 		dev_spec = 0x0;
21511da177e4SLinus Torvalds 	if (msense_6) {
21521da177e4SLinus Torvalds 		arr[2] = dev_spec;
215323183910SDouglas Gilbert 		arr[3] = bd_len;
21541da177e4SLinus Torvalds 		offset = 4;
21551da177e4SLinus Torvalds 	} else {
21561da177e4SLinus Torvalds 		arr[3] = dev_spec;
215723183910SDouglas Gilbert 		if (16 == bd_len)
215823183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
215923183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
21601da177e4SLinus Torvalds 		offset = 8;
21611da177e4SLinus Torvalds 	}
21621da177e4SLinus Torvalds 	ap = arr + offset;
216328898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
216428898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
216528898873SFUJITA Tomonori 
216623183910SDouglas Gilbert 	if (8 == bd_len) {
2167773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2168773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2169773642d9SDouglas Gilbert 		else
2170773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2171773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
217223183910SDouglas Gilbert 		offset += bd_len;
217323183910SDouglas Gilbert 		ap = arr + offset;
217423183910SDouglas Gilbert 	} else if (16 == bd_len) {
2175773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2176773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
217723183910SDouglas Gilbert 		offset += bd_len;
217823183910SDouglas Gilbert 		ap = arr + offset;
217923183910SDouglas Gilbert 	}
21801da177e4SLinus Torvalds 
2181c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2182c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
218322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
21841da177e4SLinus Torvalds 		return check_condition_result;
21851da177e4SLinus Torvalds 	}
2186760f3b03SDouglas Gilbert 	bad_pcode = false;
2187760f3b03SDouglas Gilbert 
21881da177e4SLinus Torvalds 	switch (pcode) {
21891da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
21901da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
21911da177e4SLinus Torvalds 		offset += len;
21921da177e4SLinus Torvalds 		break;
21931da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
21941da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
21951da177e4SLinus Torvalds 		offset += len;
21961da177e4SLinus Torvalds 		break;
21971da177e4SLinus Torvalds 	case 0x3:       /* Format device page, direct access */
2198760f3b03SDouglas Gilbert 		if (is_disk) {
21991da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
22001da177e4SLinus Torvalds 			offset += len;
2201760f3b03SDouglas Gilbert 		} else
2202760f3b03SDouglas Gilbert 			bad_pcode = true;
22031da177e4SLinus Torvalds 		break;
22041da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2205760f3b03SDouglas Gilbert 		if (is_disk) {
22061da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
22071da177e4SLinus Torvalds 			offset += len;
2208760f3b03SDouglas Gilbert 		} else
2209760f3b03SDouglas Gilbert 			bad_pcode = true;
22101da177e4SLinus Torvalds 		break;
22111da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
22121da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
22131da177e4SLinus Torvalds 		offset += len;
22141da177e4SLinus Torvalds 		break;
2215c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2216c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
221722017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2218c65b1445SDouglas Gilbert 			return check_condition_result;
2219c65b1445SDouglas Gilbert 		}
2220c65b1445SDouglas Gilbert 		len = 0;
2221c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2222c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2223c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2224c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2225c65b1445SDouglas Gilbert 						  target_dev_id);
2226c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2227c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2228c65b1445SDouglas Gilbert 		offset += len;
2229c65b1445SDouglas Gilbert 		break;
22301da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
22311da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
22321da177e4SLinus Torvalds 		offset += len;
22331da177e4SLinus Torvalds 		break;
22341da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2235c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
22361da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
22371da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2238760f3b03SDouglas Gilbert 			if (is_disk) {
2239760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2240760f3b03SDouglas Gilbert 						      target);
2241760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2242760f3b03SDouglas Gilbert 						       target);
2243760f3b03SDouglas Gilbert 			}
22441da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2245c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2246c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2247c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2248c65b1445SDouglas Gilbert 						  target, target_dev_id);
2249c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2250c65b1445SDouglas Gilbert 			}
22511da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2252760f3b03SDouglas Gilbert 			offset += len;
2253c65b1445SDouglas Gilbert 		} else {
225422017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2255c65b1445SDouglas Gilbert 			return check_condition_result;
2256c65b1445SDouglas Gilbert 		}
22571da177e4SLinus Torvalds 		break;
22581da177e4SLinus Torvalds 	default:
2259760f3b03SDouglas Gilbert 		bad_pcode = true;
2260760f3b03SDouglas Gilbert 		break;
2261760f3b03SDouglas Gilbert 	}
2262760f3b03SDouglas Gilbert 	if (bad_pcode) {
226322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
22641da177e4SLinus Torvalds 		return check_condition_result;
22651da177e4SLinus Torvalds 	}
22661da177e4SLinus Torvalds 	if (msense_6)
22671da177e4SLinus Torvalds 		arr[0] = offset - 1;
2268773642d9SDouglas Gilbert 	else
2269773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
22701da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
22711da177e4SLinus Torvalds }
22721da177e4SLinus Torvalds 
2273c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2274c65b1445SDouglas Gilbert 
2275fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2276fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2277c65b1445SDouglas Gilbert {
2278c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2279c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2280c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
228101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2282c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2283c65b1445SDouglas Gilbert 
2284c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2285c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2286c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2287773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2288c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
228922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2290c65b1445SDouglas Gilbert 		return check_condition_result;
2291c65b1445SDouglas Gilbert 	}
2292c65b1445SDouglas Gilbert 	res = fetch_to_dev_buffer(scp, arr, param_len);
2293c65b1445SDouglas Gilbert 	if (-1 == res)
2294773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2295773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2296cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2297cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2298cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2299773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2300773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
230123183910SDouglas Gilbert 	if (md_len > 2) {
230222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2303c65b1445SDouglas Gilbert 		return check_condition_result;
2304c65b1445SDouglas Gilbert 	}
2305c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2306c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2307c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2308c65b1445SDouglas Gilbert 	if (ps) {
230922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2310c65b1445SDouglas Gilbert 		return check_condition_result;
2311c65b1445SDouglas Gilbert 	}
2312c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2313773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2314c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2315c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2316cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2317c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2318c65b1445SDouglas Gilbert 		return check_condition_result;
2319c65b1445SDouglas Gilbert 	}
2320c65b1445SDouglas Gilbert 	switch (mpage) {
2321cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2322cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2323cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2324cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2325cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2326cbf67842SDouglas Gilbert 		}
2327cbf67842SDouglas Gilbert 		break;
2328c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2329c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2330c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2331c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
2332773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2333cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2334c65b1445SDouglas Gilbert 		}
2335c65b1445SDouglas Gilbert 		break;
2336c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2337c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2338c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2339c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2340cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2341c65b1445SDouglas Gilbert 		}
2342c65b1445SDouglas Gilbert 		break;
2343c65b1445SDouglas Gilbert 	default:
2344c65b1445SDouglas Gilbert 		break;
2345c65b1445SDouglas Gilbert 	}
234622017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2347c65b1445SDouglas Gilbert 	return check_condition_result;
2348cbf67842SDouglas Gilbert set_mode_changed_ua:
2349cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2350cbf67842SDouglas Gilbert 	return 0;
2351c65b1445SDouglas Gilbert }
2352c65b1445SDouglas Gilbert 
2353c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr)
2354c65b1445SDouglas Gilbert {
2355c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2356c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2357c65b1445SDouglas Gilbert 		};
2358c65b1445SDouglas Gilbert 
2359c65b1445SDouglas Gilbert 	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2360c65b1445SDouglas Gilbert 	return sizeof(temp_l_pg);
2361c65b1445SDouglas Gilbert }
2362c65b1445SDouglas Gilbert 
2363c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr)
2364c65b1445SDouglas Gilbert {
2365c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2366c65b1445SDouglas Gilbert 		};
2367c65b1445SDouglas Gilbert 
2368c65b1445SDouglas Gilbert 	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2369c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2370c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2371c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2372c65b1445SDouglas Gilbert 	}
2373c65b1445SDouglas Gilbert 	return sizeof(ie_l_pg);
2374c65b1445SDouglas Gilbert }
2375c65b1445SDouglas Gilbert 
2376c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2377c65b1445SDouglas Gilbert 
2378c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp,
2379c65b1445SDouglas Gilbert 			  struct sdebug_dev_info *devip)
2380c65b1445SDouglas Gilbert {
2381ab17241cSBart Van Assche 	int ppc, sp, pcode, subpcode, alloc_len, len, n;
2382c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
238301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2384c65b1445SDouglas Gilbert 
2385c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2386c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2387c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2388c65b1445SDouglas Gilbert 	if (ppc || sp) {
238922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2390c65b1445SDouglas Gilbert 		return check_condition_result;
2391c65b1445SDouglas Gilbert 	}
2392c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
239323183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2394773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2395c65b1445SDouglas Gilbert 	arr[0] = pcode;
239623183910SDouglas Gilbert 	if (0 == subpcode) {
2397c65b1445SDouglas Gilbert 		switch (pcode) {
2398c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2399c65b1445SDouglas Gilbert 			n = 4;
2400c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2401c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2402c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2403c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2404c65b1445SDouglas Gilbert 			break;
2405c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2406c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2407c65b1445SDouglas Gilbert 			break;
2408c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2409c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2410c65b1445SDouglas Gilbert 			break;
2411c65b1445SDouglas Gilbert 		default:
241222017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2413c65b1445SDouglas Gilbert 			return check_condition_result;
2414c65b1445SDouglas Gilbert 		}
241523183910SDouglas Gilbert 	} else if (0xff == subpcode) {
241623183910SDouglas Gilbert 		arr[0] |= 0x40;
241723183910SDouglas Gilbert 		arr[1] = subpcode;
241823183910SDouglas Gilbert 		switch (pcode) {
241923183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
242023183910SDouglas Gilbert 			n = 4;
242123183910SDouglas Gilbert 			arr[n++] = 0x0;
242223183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
242323183910SDouglas Gilbert 			arr[n++] = 0x0;
242423183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
242523183910SDouglas Gilbert 			arr[n++] = 0xd;
242623183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
242723183910SDouglas Gilbert 			arr[n++] = 0x2f;
242823183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
242923183910SDouglas Gilbert 			arr[3] = n - 4;
243023183910SDouglas Gilbert 			break;
243123183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
243223183910SDouglas Gilbert 			n = 4;
243323183910SDouglas Gilbert 			arr[n++] = 0xd;
243423183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
243523183910SDouglas Gilbert 			arr[3] = n - 4;
243623183910SDouglas Gilbert 			break;
243723183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
243823183910SDouglas Gilbert 			n = 4;
243923183910SDouglas Gilbert 			arr[n++] = 0x2f;
244023183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
244123183910SDouglas Gilbert 			arr[3] = n - 4;
244223183910SDouglas Gilbert 			break;
244323183910SDouglas Gilbert 		default:
244422017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
244523183910SDouglas Gilbert 			return check_condition_result;
244623183910SDouglas Gilbert 		}
244723183910SDouglas Gilbert 	} else {
244822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
244923183910SDouglas Gilbert 		return check_condition_result;
245023183910SDouglas Gilbert 	}
2451773642d9SDouglas Gilbert 	len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
2452c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
2453c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
2454c65b1445SDouglas Gilbert }
2455c65b1445SDouglas Gilbert 
2456cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp,
245719789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
24581da177e4SLinus Torvalds {
2459c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
246022017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
24611da177e4SLinus Torvalds 		return check_condition_result;
24621da177e4SLinus Torvalds 	}
2463c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2464c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
246522017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2466cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2467c65b1445SDouglas Gilbert 		return check_condition_result;
2468c65b1445SDouglas Gilbert 	}
246919789100SFUJITA Tomonori 	return 0;
247019789100SFUJITA Tomonori }
247119789100SFUJITA Tomonori 
2472a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
24730a7e69c7SDouglas Gilbert static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
24740a7e69c7SDouglas Gilbert 			    u32 num, bool do_write)
247519789100SFUJITA Tomonori {
247619789100SFUJITA Tomonori 	int ret;
2477c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2478a4517511SAkinobu Mita 	struct scsi_data_buffer *sdb;
2479a4517511SAkinobu Mita 	enum dma_data_direction dir;
248019789100SFUJITA Tomonori 
2481c2248fc9SDouglas Gilbert 	if (do_write) {
2482a4517511SAkinobu Mita 		sdb = scsi_out(scmd);
2483a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
24844f2c8bf6SDouglas Gilbert 		write_since_sync = true;
2485a4517511SAkinobu Mita 	} else {
2486a4517511SAkinobu Mita 		sdb = scsi_in(scmd);
2487a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2488a4517511SAkinobu Mita 	}
2489a4517511SAkinobu Mita 
2490a4517511SAkinobu Mita 	if (!sdb->length)
2491a4517511SAkinobu Mita 		return 0;
2492a4517511SAkinobu Mita 	if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2493a4517511SAkinobu Mita 		return -1;
249419789100SFUJITA Tomonori 
249519789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
249619789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
249719789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
249819789100SFUJITA Tomonori 
2499386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2500773642d9SDouglas Gilbert 		   fake_storep + (block * sdebug_sector_size),
25010a7e69c7SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
2502773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2503a4517511SAkinobu Mita 		return ret;
2504a4517511SAkinobu Mita 
2505a4517511SAkinobu Mita 	if (rest) {
2506386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2507773642d9SDouglas Gilbert 			    fake_storep, rest * sdebug_sector_size,
25080a7e69c7SDouglas Gilbert 			    sg_skip + ((num - rest) * sdebug_sector_size),
25090a7e69c7SDouglas Gilbert 			    do_write);
2510a4517511SAkinobu Mita 	}
251119789100SFUJITA Tomonori 
251219789100SFUJITA Tomonori 	return ret;
251319789100SFUJITA Tomonori }
251419789100SFUJITA Tomonori 
251538d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of
251638d5c833SDouglas Gilbert  * arr into fake_store(lba,num) and return true. If comparison fails then
251738d5c833SDouglas Gilbert  * return false. */
2518fd32119bSDouglas Gilbert static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
251938d5c833SDouglas Gilbert {
252038d5c833SDouglas Gilbert 	bool res;
252138d5c833SDouglas Gilbert 	u64 block, rest = 0;
252238d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2523773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
252438d5c833SDouglas Gilbert 
252538d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
252638d5c833SDouglas Gilbert 	if (block + num > store_blks)
252738d5c833SDouglas Gilbert 		rest = block + num - store_blks;
252838d5c833SDouglas Gilbert 
252938d5c833SDouglas Gilbert 	res = !memcmp(fake_storep + (block * lb_size), arr,
253038d5c833SDouglas Gilbert 		      (num - rest) * lb_size);
253138d5c833SDouglas Gilbert 	if (!res)
253238d5c833SDouglas Gilbert 		return res;
253338d5c833SDouglas Gilbert 	if (rest)
253438d5c833SDouglas Gilbert 		res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
253538d5c833SDouglas Gilbert 			     rest * lb_size);
253638d5c833SDouglas Gilbert 	if (!res)
253738d5c833SDouglas Gilbert 		return res;
253838d5c833SDouglas Gilbert 	arr += num * lb_size;
253938d5c833SDouglas Gilbert 	memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
254038d5c833SDouglas Gilbert 	if (rest)
254138d5c833SDouglas Gilbert 		memcpy(fake_storep, arr + ((num - rest) * lb_size),
254238d5c833SDouglas Gilbert 		       rest * lb_size);
254338d5c833SDouglas Gilbert 	return res;
254438d5c833SDouglas Gilbert }
254538d5c833SDouglas Gilbert 
254651d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2547beb40ea4SAkinobu Mita {
254851d648afSAkinobu Mita 	__be16 csum;
2549beb40ea4SAkinobu Mita 
2550773642d9SDouglas Gilbert 	if (sdebug_guard)
255151d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
255251d648afSAkinobu Mita 	else
2553beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
255451d648afSAkinobu Mita 
2555beb40ea4SAkinobu Mita 	return csum;
2556beb40ea4SAkinobu Mita }
2557beb40ea4SAkinobu Mita 
25586ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
2559beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
2560beb40ea4SAkinobu Mita {
2561773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
2562beb40ea4SAkinobu Mita 
2563beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
2564c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
2565beb40ea4SAkinobu Mita 			(unsigned long)sector,
2566beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
2567beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
2568beb40ea4SAkinobu Mita 		return 0x01;
2569beb40ea4SAkinobu Mita 	}
25708475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
2571beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
2572c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2573c1287970STomas Winkler 			(unsigned long)sector);
2574beb40ea4SAkinobu Mita 		return 0x03;
2575beb40ea4SAkinobu Mita 	}
25768475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2577beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
2578c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2579c1287970STomas Winkler 			(unsigned long)sector);
2580beb40ea4SAkinobu Mita 		return 0x03;
2581beb40ea4SAkinobu Mita 	}
2582beb40ea4SAkinobu Mita 	return 0;
2583beb40ea4SAkinobu Mita }
2584beb40ea4SAkinobu Mita 
2585bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
258665f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
2587c6a44287SMartin K. Petersen {
2588be4e11beSAkinobu Mita 	size_t resid;
2589c6a44287SMartin K. Petersen 	void *paddr;
259014faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
2591be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
2592c6a44287SMartin K. Petersen 
2593e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
2594e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
2595c6a44287SMartin K. Petersen 
2596be4e11beSAkinobu Mita 	sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2597be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2598be4e11beSAkinobu Mita 			(read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2599be4e11beSAkinobu Mita 
2600be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
2601be4e11beSAkinobu Mita 		size_t len = min(miter.length, resid);
260214faa944SAkinobu Mita 		void *start = dif_store(sector);
2603be4e11beSAkinobu Mita 		size_t rest = 0;
260414faa944SAkinobu Mita 
260514faa944SAkinobu Mita 		if (dif_store_end < start + len)
260614faa944SAkinobu Mita 			rest = start + len - dif_store_end;
2607c6a44287SMartin K. Petersen 
2608be4e11beSAkinobu Mita 		paddr = miter.addr;
260914faa944SAkinobu Mita 
261065f72f2aSAkinobu Mita 		if (read)
261165f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
261265f72f2aSAkinobu Mita 		else
261365f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
261465f72f2aSAkinobu Mita 
261565f72f2aSAkinobu Mita 		if (rest) {
261665f72f2aSAkinobu Mita 			if (read)
261714faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
261865f72f2aSAkinobu Mita 			else
261965f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
262065f72f2aSAkinobu Mita 		}
2621c6a44287SMartin K. Petersen 
2622e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
2623c6a44287SMartin K. Petersen 		resid -= len;
2624c6a44287SMartin K. Petersen 	}
2625be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
2626bb8c063cSAkinobu Mita }
2627c6a44287SMartin K. Petersen 
2628bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2629bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
2630bb8c063cSAkinobu Mita {
2631bb8c063cSAkinobu Mita 	unsigned int i;
26326ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
2633bb8c063cSAkinobu Mita 	sector_t sector;
2634bb8c063cSAkinobu Mita 
2635c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
2636bb8c063cSAkinobu Mita 		int ret;
2637bb8c063cSAkinobu Mita 
2638bb8c063cSAkinobu Mita 		sector = start_sec + i;
2639bb8c063cSAkinobu Mita 		sdt = dif_store(sector);
2640bb8c063cSAkinobu Mita 
264151d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
2642bb8c063cSAkinobu Mita 			continue;
2643bb8c063cSAkinobu Mita 
2644bb8c063cSAkinobu Mita 		ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2645bb8c063cSAkinobu Mita 		if (ret) {
2646bb8c063cSAkinobu Mita 			dif_errors++;
2647bb8c063cSAkinobu Mita 			return ret;
2648bb8c063cSAkinobu Mita 		}
2649bb8c063cSAkinobu Mita 	}
2650bb8c063cSAkinobu Mita 
265165f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, true);
2652c6a44287SMartin K. Petersen 	dix_reads++;
2653c6a44287SMartin K. Petersen 
2654c6a44287SMartin K. Petersen 	return 0;
2655c6a44287SMartin K. Petersen }
2656c6a44287SMartin K. Petersen 
2657fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
265819789100SFUJITA Tomonori {
2659c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2660c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
2661c2248fc9SDouglas Gilbert 	u64 lba;
2662c2248fc9SDouglas Gilbert 	u32 num;
2663c2248fc9SDouglas Gilbert 	u32 ei_lba;
266419789100SFUJITA Tomonori 	unsigned long iflags;
266519789100SFUJITA Tomonori 	int ret;
2666c2248fc9SDouglas Gilbert 	bool check_prot;
266719789100SFUJITA Tomonori 
2668c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2669c2248fc9SDouglas Gilbert 	case READ_16:
2670c2248fc9SDouglas Gilbert 		ei_lba = 0;
2671c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2672c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2673c2248fc9SDouglas Gilbert 		check_prot = true;
2674c2248fc9SDouglas Gilbert 		break;
2675c2248fc9SDouglas Gilbert 	case READ_10:
2676c2248fc9SDouglas Gilbert 		ei_lba = 0;
2677c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2678c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2679c2248fc9SDouglas Gilbert 		check_prot = true;
2680c2248fc9SDouglas Gilbert 		break;
2681c2248fc9SDouglas Gilbert 	case READ_6:
2682c2248fc9SDouglas Gilbert 		ei_lba = 0;
2683c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2684c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2685c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2686c2248fc9SDouglas Gilbert 		check_prot = true;
2687c2248fc9SDouglas Gilbert 		break;
2688c2248fc9SDouglas Gilbert 	case READ_12:
2689c2248fc9SDouglas Gilbert 		ei_lba = 0;
2690c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2691c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2692c2248fc9SDouglas Gilbert 		check_prot = true;
2693c2248fc9SDouglas Gilbert 		break;
2694c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
2695c2248fc9SDouglas Gilbert 		ei_lba = 0;
2696c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2697c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2698c2248fc9SDouglas Gilbert 		check_prot = false;
2699c2248fc9SDouglas Gilbert 		break;
2700c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
2701c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2702c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2703c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2704c2248fc9SDouglas Gilbert 		check_prot = false;
2705c2248fc9SDouglas Gilbert 		break;
2706c2248fc9SDouglas Gilbert 	}
2707f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
27088475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2709c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2710c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2711c2248fc9SDouglas Gilbert 			return check_condition_result;
2712c2248fc9SDouglas Gilbert 		}
27138475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
27148475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
2715c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2716c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2717c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2718c2248fc9SDouglas Gilbert 	}
2719f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
2720c4837394SDouglas Gilbert 		sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
2721c2248fc9SDouglas Gilbert 
2722c4837394SDouglas Gilbert 		if (sqcp) {
2723c4837394SDouglas Gilbert 			if (sqcp->inj_short)
2724c2248fc9SDouglas Gilbert 				num /= 2;
2725c2248fc9SDouglas Gilbert 		}
2726c4837394SDouglas Gilbert 	} else
2727c4837394SDouglas Gilbert 		sqcp = NULL;
2728c2248fc9SDouglas Gilbert 
2729c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2730f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
2731c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2732c2248fc9SDouglas Gilbert 		return check_condition_result;
2733c2248fc9SDouglas Gilbert 	}
2734c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2735f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
2736c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2737c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2738c2248fc9SDouglas Gilbert 		return check_condition_result;
2739c2248fc9SDouglas Gilbert 	}
274019789100SFUJITA Tomonori 
2741f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
2742d9da891aSLaurence Oberman 		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
2743d9da891aSLaurence Oberman 		     ((lba + num) > sdebug_medium_error_start))) {
2744c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
2745c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
2746c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
2747c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2748c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
274932f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
275032f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
2751c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
2752c65b1445SDouglas Gilbert 		}
2753c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
27541da177e4SLinus Torvalds 		return check_condition_result;
27551da177e4SLinus Torvalds 	}
2756c6a44287SMartin K. Petersen 
27576c78cc06SAkinobu Mita 	read_lock_irqsave(&atomic_rw, iflags);
27586c78cc06SAkinobu Mita 
2759c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2760f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
2761c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
2762c6a44287SMartin K. Petersen 
2763c6a44287SMartin K. Petersen 		if (prot_ret) {
27646c78cc06SAkinobu Mita 			read_unlock_irqrestore(&atomic_rw, iflags);
2765c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
2766c6a44287SMartin K. Petersen 			return illegal_condition_result;
2767c6a44287SMartin K. Petersen 		}
2768c6a44287SMartin K. Petersen 	}
2769c6a44287SMartin K. Petersen 
27700a7e69c7SDouglas Gilbert 	ret = do_device_access(scp, 0, lba, num, false);
27711da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
2772f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
2773a4517511SAkinobu Mita 		return DID_ERROR << 16;
2774a4517511SAkinobu Mita 
2775c2248fc9SDouglas Gilbert 	scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
2776a4517511SAkinobu Mita 
2777c4837394SDouglas Gilbert 	if (unlikely(sqcp)) {
2778c4837394SDouglas Gilbert 		if (sqcp->inj_recovered) {
2779c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
2780c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
2781c2248fc9SDouglas Gilbert 			return check_condition_result;
2782c4837394SDouglas Gilbert 		} else if (sqcp->inj_transport) {
2783c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND,
2784c2248fc9SDouglas Gilbert 					TRANSPORT_PROBLEM, ACK_NAK_TO);
2785c2248fc9SDouglas Gilbert 			return check_condition_result;
2786c4837394SDouglas Gilbert 		} else if (sqcp->inj_dif) {
2787c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
2788c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2789c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2790c4837394SDouglas Gilbert 		} else if (sqcp->inj_dix) {
2791c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2792c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2793c2248fc9SDouglas Gilbert 		}
2794c2248fc9SDouglas Gilbert 	}
2795a4517511SAkinobu Mita 	return 0;
27961da177e4SLinus Torvalds }
27971da177e4SLinus Torvalds 
279858a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len)
2799c6a44287SMartin K. Petersen {
2800cbf67842SDouglas Gilbert 	int i, j, n;
2801c6a44287SMartin K. Petersen 
2802cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
2803c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
2804cbf67842SDouglas Gilbert 		char b[128];
2805c6a44287SMartin K. Petersen 
2806cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
2807c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
2808c6a44287SMartin K. Petersen 
2809cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
2810cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2811cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
2812cbf67842SDouglas Gilbert 			else
2813cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2814cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
2815cbf67842SDouglas Gilbert 		}
2816cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
2817c6a44287SMartin K. Petersen 	}
2818c6a44287SMartin K. Petersen }
2819c6a44287SMartin K. Petersen 
2820c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
2821395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
2822c6a44287SMartin K. Petersen {
2823be4e11beSAkinobu Mita 	int ret;
28246ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
2825be4e11beSAkinobu Mita 	void *daddr;
282665f72f2aSAkinobu Mita 	sector_t sector = start_sec;
2827c6a44287SMartin K. Petersen 	int ppage_offset;
2828be4e11beSAkinobu Mita 	int dpage_offset;
2829be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
2830be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
2831c6a44287SMartin K. Petersen 
2832c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
2833c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2834c6a44287SMartin K. Petersen 
2835be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2836be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
2837be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2838be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2839be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2840c6a44287SMartin K. Petersen 
2841be4e11beSAkinobu Mita 	/* For each protection page */
2842be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
2843be4e11beSAkinobu Mita 		dpage_offset = 0;
2844be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
2845be4e11beSAkinobu Mita 			ret = 0x01;
2846be4e11beSAkinobu Mita 			goto out;
2847c6a44287SMartin K. Petersen 		}
2848c6a44287SMartin K. Petersen 
2849be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
28506ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
2851be4e11beSAkinobu Mita 			/* If we're at the end of the current
2852be4e11beSAkinobu Mita 			 * data page advance to the next one
2853be4e11beSAkinobu Mita 			 */
2854be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
2855be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
2856be4e11beSAkinobu Mita 					ret = 0x01;
2857be4e11beSAkinobu Mita 					goto out;
2858be4e11beSAkinobu Mita 				}
2859be4e11beSAkinobu Mita 				dpage_offset = 0;
2860be4e11beSAkinobu Mita 			}
2861c6a44287SMartin K. Petersen 
2862be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
2863be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
2864be4e11beSAkinobu Mita 
2865be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
2866beb40ea4SAkinobu Mita 			if (ret) {
2867773642d9SDouglas Gilbert 				dump_sector(daddr, sdebug_sector_size);
2868395cef03SMartin K. Petersen 				goto out;
2869395cef03SMartin K. Petersen 			}
2870395cef03SMartin K. Petersen 
2871c6a44287SMartin K. Petersen 			sector++;
2872395cef03SMartin K. Petersen 			ei_lba++;
2873773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
2874c6a44287SMartin K. Petersen 		}
2875be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
2876be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
2877c6a44287SMartin K. Petersen 	}
2878be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2879c6a44287SMartin K. Petersen 
288065f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
2881c6a44287SMartin K. Petersen 	dix_writes++;
2882c6a44287SMartin K. Petersen 
2883c6a44287SMartin K. Petersen 	return 0;
2884c6a44287SMartin K. Petersen 
2885c6a44287SMartin K. Petersen out:
2886c6a44287SMartin K. Petersen 	dif_errors++;
2887be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
2888be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2889c6a44287SMartin K. Petersen 	return ret;
2890c6a44287SMartin K. Petersen }
2891c6a44287SMartin K. Petersen 
2892b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
2893b90ebc3dSAkinobu Mita {
2894773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2895773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2896773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
2897b90ebc3dSAkinobu Mita 	return lba;
2898b90ebc3dSAkinobu Mita }
2899b90ebc3dSAkinobu Mita 
2900b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
2901b90ebc3dSAkinobu Mita {
2902773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
2903a027b5b9SAkinobu Mita 
2904773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2905773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
2906a027b5b9SAkinobu Mita 	return lba;
2907a027b5b9SAkinobu Mita }
2908a027b5b9SAkinobu Mita 
290944d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
291044d92694SMartin K. Petersen {
2911b90ebc3dSAkinobu Mita 	sector_t end;
2912b90ebc3dSAkinobu Mita 	unsigned int mapped;
2913b90ebc3dSAkinobu Mita 	unsigned long index;
2914b90ebc3dSAkinobu Mita 	unsigned long next;
291544d92694SMartin K. Petersen 
2916b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
2917b90ebc3dSAkinobu Mita 	mapped = test_bit(index, map_storep);
291844d92694SMartin K. Petersen 
291944d92694SMartin K. Petersen 	if (mapped)
2920b90ebc3dSAkinobu Mita 		next = find_next_zero_bit(map_storep, map_size, index);
292144d92694SMartin K. Petersen 	else
2922b90ebc3dSAkinobu Mita 		next = find_next_bit(map_storep, map_size, index);
292344d92694SMartin K. Petersen 
2924b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
292544d92694SMartin K. Petersen 	*num = end - lba;
292644d92694SMartin K. Petersen 	return mapped;
292744d92694SMartin K. Petersen }
292844d92694SMartin K. Petersen 
292944d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
293044d92694SMartin K. Petersen {
293144d92694SMartin K. Petersen 	sector_t end = lba + len;
293244d92694SMartin K. Petersen 
293344d92694SMartin K. Petersen 	while (lba < end) {
2934b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
293544d92694SMartin K. Petersen 
2936b90ebc3dSAkinobu Mita 		if (index < map_size)
2937b90ebc3dSAkinobu Mita 			set_bit(index, map_storep);
293844d92694SMartin K. Petersen 
2939b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
294044d92694SMartin K. Petersen 	}
294144d92694SMartin K. Petersen }
294244d92694SMartin K. Petersen 
294344d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
294444d92694SMartin K. Petersen {
294544d92694SMartin K. Petersen 	sector_t end = lba + len;
294644d92694SMartin K. Petersen 
294744d92694SMartin K. Petersen 	while (lba < end) {
2948b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
294944d92694SMartin K. Petersen 
2950b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
2951773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
2952b90ebc3dSAkinobu Mita 		    index < map_size) {
2953b90ebc3dSAkinobu Mita 			clear_bit(index, map_storep);
2954760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
2955be1dd78dSEric Sandeen 				memset(fake_storep +
2956760f3b03SDouglas Gilbert 				       lba * sdebug_sector_size,
2957760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
2958773642d9SDouglas Gilbert 				       sdebug_sector_size *
2959773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2960be1dd78dSEric Sandeen 			}
2961e9926b43SAkinobu Mita 			if (dif_storep) {
2962e9926b43SAkinobu Mita 				memset(dif_storep + lba, 0xff,
2963e9926b43SAkinobu Mita 				       sizeof(*dif_storep) *
2964773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2965e9926b43SAkinobu Mita 			}
2966b90ebc3dSAkinobu Mita 		}
2967b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
296844d92694SMartin K. Petersen 	}
296944d92694SMartin K. Petersen }
297044d92694SMartin K. Petersen 
2971fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
29721da177e4SLinus Torvalds {
2973c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2974c2248fc9SDouglas Gilbert 	u64 lba;
2975c2248fc9SDouglas Gilbert 	u32 num;
2976c2248fc9SDouglas Gilbert 	u32 ei_lba;
29771da177e4SLinus Torvalds 	unsigned long iflags;
297819789100SFUJITA Tomonori 	int ret;
2979c2248fc9SDouglas Gilbert 	bool check_prot;
29801da177e4SLinus Torvalds 
2981c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2982c2248fc9SDouglas Gilbert 	case WRITE_16:
2983c2248fc9SDouglas Gilbert 		ei_lba = 0;
2984c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2985c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2986c2248fc9SDouglas Gilbert 		check_prot = true;
2987c2248fc9SDouglas Gilbert 		break;
2988c2248fc9SDouglas Gilbert 	case WRITE_10:
2989c2248fc9SDouglas Gilbert 		ei_lba = 0;
2990c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2991c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2992c2248fc9SDouglas Gilbert 		check_prot = true;
2993c2248fc9SDouglas Gilbert 		break;
2994c2248fc9SDouglas Gilbert 	case WRITE_6:
2995c2248fc9SDouglas Gilbert 		ei_lba = 0;
2996c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2997c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2998c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2999c2248fc9SDouglas Gilbert 		check_prot = true;
3000c2248fc9SDouglas Gilbert 		break;
3001c2248fc9SDouglas Gilbert 	case WRITE_12:
3002c2248fc9SDouglas Gilbert 		ei_lba = 0;
3003c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3004c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
3005c2248fc9SDouglas Gilbert 		check_prot = true;
3006c2248fc9SDouglas Gilbert 		break;
3007c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
3008c2248fc9SDouglas Gilbert 		ei_lba = 0;
3009c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
3010c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
3011c2248fc9SDouglas Gilbert 		check_prot = false;
3012c2248fc9SDouglas Gilbert 		break;
3013c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
3014c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
3015c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
3016c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
3017c2248fc9SDouglas Gilbert 		check_prot = false;
3018c2248fc9SDouglas Gilbert 		break;
3019c2248fc9SDouglas Gilbert 	}
3020f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
30218475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3022c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
3023c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
3024c2248fc9SDouglas Gilbert 			return check_condition_result;
3025c2248fc9SDouglas Gilbert 		}
30268475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
30278475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3028c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
3029c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3030c2248fc9SDouglas Gilbert 				    "to DIF device\n");
3031c2248fc9SDouglas Gilbert 	}
3032c2248fc9SDouglas Gilbert 
3033c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
3034f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
3035c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3036c2248fc9SDouglas Gilbert 		return check_condition_result;
3037c2248fc9SDouglas Gilbert 	}
3038c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
3039f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
3040c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
3041c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3042c2248fc9SDouglas Gilbert 		return check_condition_result;
3043c2248fc9SDouglas Gilbert 	}
30441da177e4SLinus Torvalds 
30456c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
30466c78cc06SAkinobu Mita 
3047c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
3048f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3049c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
3050c6a44287SMartin K. Petersen 
3051c6a44287SMartin K. Petersen 		if (prot_ret) {
30526c78cc06SAkinobu Mita 			write_unlock_irqrestore(&atomic_rw, iflags);
3053c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
3054c6a44287SMartin K. Petersen 			return illegal_condition_result;
3055c6a44287SMartin K. Petersen 		}
3056c6a44287SMartin K. Petersen 	}
3057c6a44287SMartin K. Petersen 
30580a7e69c7SDouglas Gilbert 	ret = do_device_access(scp, 0, lba, num, true);
3059f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
306044d92694SMartin K. Petersen 		map_region(lba, num);
30611da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
3062f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
3063773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3064c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
3065c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
3066c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3067cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3068773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
306944d92694SMartin K. Petersen 
3070f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
3071c4837394SDouglas Gilbert 		struct sdebug_queued_cmd *sqcp =
3072c4837394SDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
3073c2248fc9SDouglas Gilbert 
3074c4837394SDouglas Gilbert 		if (sqcp) {
3075c4837394SDouglas Gilbert 			if (sqcp->inj_recovered) {
3076c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR,
3077c2248fc9SDouglas Gilbert 						THRESHOLD_EXCEEDED, 0);
3078c2248fc9SDouglas Gilbert 				return check_condition_result;
3079c4837394SDouglas Gilbert 			} else if (sqcp->inj_dif) {
3080c2248fc9SDouglas Gilbert 				/* Logical block guard check failed */
3081c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3082c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3083c4837394SDouglas Gilbert 			} else if (sqcp->inj_dix) {
3084c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3085c2248fc9SDouglas Gilbert 				return illegal_condition_result;
3086c2248fc9SDouglas Gilbert 			}
3087c2248fc9SDouglas Gilbert 		}
3088c4837394SDouglas Gilbert 	}
30891da177e4SLinus Torvalds 	return 0;
30901da177e4SLinus Torvalds }
30911da177e4SLinus Torvalds 
3092481b5e5cSDouglas Gilbert /*
3093481b5e5cSDouglas Gilbert  * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3094481b5e5cSDouglas Gilbert  * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3095481b5e5cSDouglas Gilbert  */
3096481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp,
3097481b5e5cSDouglas Gilbert 			   struct sdebug_dev_info *devip)
3098481b5e5cSDouglas Gilbert {
3099481b5e5cSDouglas Gilbert 	u8 *cmd = scp->cmnd;
3100481b5e5cSDouglas Gilbert 	u8 *lrdp = NULL;
3101481b5e5cSDouglas Gilbert 	u8 *up;
3102481b5e5cSDouglas Gilbert 	u8 wrprotect;
3103481b5e5cSDouglas Gilbert 	u16 lbdof, num_lrd, k;
3104481b5e5cSDouglas Gilbert 	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3105481b5e5cSDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
3106481b5e5cSDouglas Gilbert 	u32 ei_lba;
3107481b5e5cSDouglas Gilbert 	u64 lba;
3108481b5e5cSDouglas Gilbert 	unsigned long iflags;
3109481b5e5cSDouglas Gilbert 	int ret, res;
3110481b5e5cSDouglas Gilbert 	bool is_16;
3111481b5e5cSDouglas Gilbert 	static const u32 lrd_size = 32; /* + parameter list header size */
3112481b5e5cSDouglas Gilbert 
3113481b5e5cSDouglas Gilbert 	if (cmd[0] == VARIABLE_LENGTH_CMD) {
3114481b5e5cSDouglas Gilbert 		is_16 = false;
3115481b5e5cSDouglas Gilbert 		wrprotect = (cmd[10] >> 5) & 0x7;
3116481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 12);
3117481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 16);
3118481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 28);
3119481b5e5cSDouglas Gilbert 	} else {        /* that leaves WRITE SCATTERED(16) */
3120481b5e5cSDouglas Gilbert 		is_16 = true;
3121481b5e5cSDouglas Gilbert 		wrprotect = (cmd[2] >> 5) & 0x7;
3122481b5e5cSDouglas Gilbert 		lbdof = get_unaligned_be16(cmd + 4);
3123481b5e5cSDouglas Gilbert 		num_lrd = get_unaligned_be16(cmd + 8);
3124481b5e5cSDouglas Gilbert 		bt_len = get_unaligned_be32(cmd + 10);
3125481b5e5cSDouglas Gilbert 		if (unlikely(have_dif_prot)) {
3126481b5e5cSDouglas Gilbert 			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3127481b5e5cSDouglas Gilbert 			    wrprotect) {
3128481b5e5cSDouglas Gilbert 				mk_sense_invalid_opcode(scp);
3129481b5e5cSDouglas Gilbert 				return illegal_condition_result;
3130481b5e5cSDouglas Gilbert 			}
3131481b5e5cSDouglas Gilbert 			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3132481b5e5cSDouglas Gilbert 			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3133481b5e5cSDouglas Gilbert 			     wrprotect == 0)
3134481b5e5cSDouglas Gilbert 				sdev_printk(KERN_ERR, scp->device,
3135481b5e5cSDouglas Gilbert 					    "Unprotected WR to DIF device\n");
3136481b5e5cSDouglas Gilbert 		}
3137481b5e5cSDouglas Gilbert 	}
3138481b5e5cSDouglas Gilbert 	if ((num_lrd == 0) || (bt_len == 0))
3139481b5e5cSDouglas Gilbert 		return 0;       /* T10 says these do-nothings are not errors */
3140481b5e5cSDouglas Gilbert 	if (lbdof == 0) {
3141481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3142481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3143481b5e5cSDouglas Gilbert 				"%s: %s: LB Data Offset field bad\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 	lbdof_blen = lbdof * lb_size;
3149481b5e5cSDouglas Gilbert 	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3150481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3151481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3152481b5e5cSDouglas Gilbert 				"%s: %s: LBA range descriptors don't fit\n",
3153481b5e5cSDouglas Gilbert 				my_name, __func__);
3154481b5e5cSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3155481b5e5cSDouglas Gilbert 		return illegal_condition_result;
3156481b5e5cSDouglas Gilbert 	}
3157481b5e5cSDouglas Gilbert 	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3158481b5e5cSDouglas Gilbert 	if (lrdp == NULL)
3159481b5e5cSDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
3160481b5e5cSDouglas Gilbert 	if (sdebug_verbose)
3161481b5e5cSDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3162481b5e5cSDouglas Gilbert 			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3163481b5e5cSDouglas Gilbert 			my_name, __func__, lbdof_blen);
3164481b5e5cSDouglas Gilbert 	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3165481b5e5cSDouglas Gilbert 	if (res == -1) {
3166481b5e5cSDouglas Gilbert 		ret = DID_ERROR << 16;
3167481b5e5cSDouglas Gilbert 		goto err_out;
3168481b5e5cSDouglas Gilbert 	}
3169481b5e5cSDouglas Gilbert 
3170481b5e5cSDouglas Gilbert 	write_lock_irqsave(&atomic_rw, iflags);
3171481b5e5cSDouglas Gilbert 	sg_off = lbdof_blen;
3172481b5e5cSDouglas Gilbert 	/* Spec says Buffer xfer Length field in number of LBs in dout */
3173481b5e5cSDouglas Gilbert 	cum_lb = 0;
3174481b5e5cSDouglas Gilbert 	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3175481b5e5cSDouglas Gilbert 		lba = get_unaligned_be64(up + 0);
3176481b5e5cSDouglas Gilbert 		num = get_unaligned_be32(up + 8);
3177481b5e5cSDouglas Gilbert 		if (sdebug_verbose)
3178481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3179481b5e5cSDouglas Gilbert 				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
3180481b5e5cSDouglas Gilbert 				my_name, __func__, k, lba, num, sg_off);
3181481b5e5cSDouglas Gilbert 		if (num == 0)
3182481b5e5cSDouglas Gilbert 			continue;
3183481b5e5cSDouglas Gilbert 		ret = check_device_access_params(scp, lba, num);
3184481b5e5cSDouglas Gilbert 		if (ret)
3185481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3186481b5e5cSDouglas Gilbert 		num_by = num * lb_size;
3187481b5e5cSDouglas Gilbert 		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3188481b5e5cSDouglas Gilbert 
3189481b5e5cSDouglas Gilbert 		if ((cum_lb + num) > bt_len) {
3190481b5e5cSDouglas Gilbert 			if (sdebug_verbose)
3191481b5e5cSDouglas Gilbert 				sdev_printk(KERN_INFO, scp->device,
3192481b5e5cSDouglas Gilbert 				    "%s: %s: sum of blocks > data provided\n",
3193481b5e5cSDouglas Gilbert 				    my_name, __func__);
3194481b5e5cSDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3195481b5e5cSDouglas Gilbert 					0);
3196481b5e5cSDouglas Gilbert 			ret = illegal_condition_result;
3197481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3198481b5e5cSDouglas Gilbert 		}
3199481b5e5cSDouglas Gilbert 
3200481b5e5cSDouglas Gilbert 		/* DIX + T10 DIF */
3201481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3202481b5e5cSDouglas Gilbert 			int prot_ret = prot_verify_write(scp, lba, num,
3203481b5e5cSDouglas Gilbert 							 ei_lba);
3204481b5e5cSDouglas Gilbert 
3205481b5e5cSDouglas Gilbert 			if (prot_ret) {
3206481b5e5cSDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3207481b5e5cSDouglas Gilbert 						prot_ret);
3208481b5e5cSDouglas Gilbert 				ret = illegal_condition_result;
3209481b5e5cSDouglas Gilbert 				goto err_out_unlock;
3210481b5e5cSDouglas Gilbert 			}
3211481b5e5cSDouglas Gilbert 		}
3212481b5e5cSDouglas Gilbert 
3213481b5e5cSDouglas Gilbert 		ret = do_device_access(scp, sg_off, lba, num, true);
3214481b5e5cSDouglas Gilbert 		if (unlikely(scsi_debug_lbp()))
3215481b5e5cSDouglas Gilbert 			map_region(lba, num);
3216481b5e5cSDouglas Gilbert 		if (unlikely(-1 == ret)) {
3217481b5e5cSDouglas Gilbert 			ret = DID_ERROR << 16;
3218481b5e5cSDouglas Gilbert 			goto err_out_unlock;
3219481b5e5cSDouglas Gilbert 		} else if (unlikely(sdebug_verbose && (ret < num_by)))
3220481b5e5cSDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
3221481b5e5cSDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3222481b5e5cSDouglas Gilbert 			    my_name, num_by, ret);
3223481b5e5cSDouglas Gilbert 
3224481b5e5cSDouglas Gilbert 		if (unlikely(sdebug_any_injecting_opt)) {
3225481b5e5cSDouglas Gilbert 			struct sdebug_queued_cmd *sqcp =
3226481b5e5cSDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
3227481b5e5cSDouglas Gilbert 
3228481b5e5cSDouglas Gilbert 			if (sqcp) {
3229481b5e5cSDouglas Gilbert 				if (sqcp->inj_recovered) {
3230481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, RECOVERED_ERROR,
3231481b5e5cSDouglas Gilbert 							THRESHOLD_EXCEEDED, 0);
3232481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3233481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3234481b5e5cSDouglas Gilbert 				} else if (sqcp->inj_dif) {
3235481b5e5cSDouglas Gilbert 					/* Logical block guard check failed */
3236481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, ABORTED_COMMAND,
3237481b5e5cSDouglas Gilbert 							0x10, 1);
3238481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3239481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3240481b5e5cSDouglas Gilbert 				} else if (sqcp->inj_dix) {
3241481b5e5cSDouglas Gilbert 					mk_sense_buffer(scp, ILLEGAL_REQUEST,
3242481b5e5cSDouglas Gilbert 							0x10, 1);
3243481b5e5cSDouglas Gilbert 					ret = illegal_condition_result;
3244481b5e5cSDouglas Gilbert 					goto err_out_unlock;
3245481b5e5cSDouglas Gilbert 				}
3246481b5e5cSDouglas Gilbert 			}
3247481b5e5cSDouglas Gilbert 		}
3248481b5e5cSDouglas Gilbert 		sg_off += num_by;
3249481b5e5cSDouglas Gilbert 		cum_lb += num;
3250481b5e5cSDouglas Gilbert 	}
3251481b5e5cSDouglas Gilbert 	ret = 0;
3252481b5e5cSDouglas Gilbert err_out_unlock:
3253481b5e5cSDouglas Gilbert 	write_unlock_irqrestore(&atomic_rw, iflags);
3254481b5e5cSDouglas Gilbert err_out:
3255481b5e5cSDouglas Gilbert 	kfree(lrdp);
3256481b5e5cSDouglas Gilbert 	return ret;
3257481b5e5cSDouglas Gilbert }
3258481b5e5cSDouglas Gilbert 
3259fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3260fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
326144d92694SMartin K. Petersen {
326244d92694SMartin K. Petersen 	unsigned long iflags;
326344d92694SMartin K. Petersen 	unsigned long long i;
326444d92694SMartin K. Petersen 	int ret;
3265773642d9SDouglas Gilbert 	u64 lba_off;
326644d92694SMartin K. Petersen 
3267c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num);
326844d92694SMartin K. Petersen 	if (ret)
326944d92694SMartin K. Petersen 		return ret;
327044d92694SMartin K. Petersen 
327144d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
327244d92694SMartin K. Petersen 
32739ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
327444d92694SMartin K. Petersen 		unmap_region(lba, num);
327544d92694SMartin K. Petersen 		goto out;
327644d92694SMartin K. Petersen 	}
327744d92694SMartin K. Petersen 
3278773642d9SDouglas Gilbert 	lba_off = lba * sdebug_sector_size;
3279c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
3280c2248fc9SDouglas Gilbert 	if (ndob) {
3281773642d9SDouglas Gilbert 		memset(fake_storep + lba_off, 0, sdebug_sector_size);
3282c2248fc9SDouglas Gilbert 		ret = 0;
3283c2248fc9SDouglas Gilbert 	} else
3284773642d9SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
3285773642d9SDouglas Gilbert 					  sdebug_sector_size);
328644d92694SMartin K. Petersen 
328744d92694SMartin K. Petersen 	if (-1 == ret) {
328844d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
3289773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3290e33d7c56SDouglas Gilbert 	} else if (sdebug_verbose && !ndob && (ret < sdebug_sector_size))
3291c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3292e33d7c56SDouglas Gilbert 			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
3293cbf67842SDouglas Gilbert 			    my_name, "write same",
3294e33d7c56SDouglas Gilbert 			    sdebug_sector_size, ret);
329544d92694SMartin K. Petersen 
329644d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
329744d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
3298773642d9SDouglas Gilbert 		memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
3299773642d9SDouglas Gilbert 		       fake_storep + lba_off,
3300773642d9SDouglas Gilbert 		       sdebug_sector_size);
330144d92694SMartin K. Petersen 
33029ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
330344d92694SMartin K. Petersen 		map_region(lba, num);
330444d92694SMartin K. Petersen out:
330544d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
330644d92694SMartin K. Petersen 
330744d92694SMartin K. Petersen 	return 0;
330844d92694SMartin K. Petersen }
330944d92694SMartin K. Petersen 
3310fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3311fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3312c2248fc9SDouglas Gilbert {
3313c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3314c2248fc9SDouglas Gilbert 	u32 lba;
3315c2248fc9SDouglas Gilbert 	u16 num;
3316c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3317c2248fc9SDouglas Gilbert 	bool unmap = false;
3318c2248fc9SDouglas Gilbert 
3319c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3320773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3321c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3322c2248fc9SDouglas Gilbert 			return check_condition_result;
3323c2248fc9SDouglas Gilbert 		} else
3324c2248fc9SDouglas Gilbert 			unmap = true;
3325c2248fc9SDouglas Gilbert 	}
3326c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3327c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3328773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3329c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3330c2248fc9SDouglas Gilbert 		return check_condition_result;
3331c2248fc9SDouglas Gilbert 	}
3332c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3333c2248fc9SDouglas Gilbert }
3334c2248fc9SDouglas Gilbert 
3335fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3336fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3337c2248fc9SDouglas Gilbert {
3338c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3339c2248fc9SDouglas Gilbert 	u64 lba;
3340c2248fc9SDouglas Gilbert 	u32 num;
3341c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3342c2248fc9SDouglas Gilbert 	bool unmap = false;
3343c2248fc9SDouglas Gilbert 	bool ndob = false;
3344c2248fc9SDouglas Gilbert 
3345c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3346773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3347c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3348c2248fc9SDouglas Gilbert 			return check_condition_result;
3349c2248fc9SDouglas Gilbert 		} else
3350c2248fc9SDouglas Gilbert 			unmap = true;
3351c2248fc9SDouglas Gilbert 	}
3352c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3353c2248fc9SDouglas Gilbert 		ndob = true;
3354c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3355c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3356773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3357c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3358c2248fc9SDouglas Gilbert 		return check_condition_result;
3359c2248fc9SDouglas Gilbert 	}
3360c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3361c2248fc9SDouglas Gilbert }
3362c2248fc9SDouglas Gilbert 
3363acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3364acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3365acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3366fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3367fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3368acafd0b9SEwan D. Milne {
3369acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3370acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3371acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3372acafd0b9SEwan D. Milne 	u8 mode;
3373acafd0b9SEwan D. Milne 
3374acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3375acafd0b9SEwan D. Milne 	switch (mode) {
3376acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3377acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3378acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3379acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3380acafd0b9SEwan D. Milne 		break;
3381acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3382acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3383acafd0b9SEwan D. Milne 		break;
3384acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3385acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3386acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3387acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3388acafd0b9SEwan D. Milne 				    dev_list)
3389acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3390acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3391acafd0b9SEwan D. Milne 				if (devip != dp)
3392acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3393acafd0b9SEwan D. Milne 						dp->uas_bm);
3394acafd0b9SEwan D. Milne 			}
3395acafd0b9SEwan D. Milne 		break;
3396acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3397acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3398acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3399acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3400acafd0b9SEwan D. Milne 				    dev_list)
3401acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3402acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3403acafd0b9SEwan D. Milne 					dp->uas_bm);
3404acafd0b9SEwan D. Milne 		break;
3405acafd0b9SEwan D. Milne 	default:
3406acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3407acafd0b9SEwan D. Milne 		break;
3408acafd0b9SEwan D. Milne 	}
3409acafd0b9SEwan D. Milne 	return 0;
3410acafd0b9SEwan D. Milne }
3411acafd0b9SEwan D. Milne 
3412fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3413fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
341438d5c833SDouglas Gilbert {
341538d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
341638d5c833SDouglas Gilbert 	u8 *arr;
341738d5c833SDouglas Gilbert 	u8 *fake_storep_hold;
341838d5c833SDouglas Gilbert 	u64 lba;
341938d5c833SDouglas Gilbert 	u32 dnum;
3420773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
342138d5c833SDouglas Gilbert 	u8 num;
342238d5c833SDouglas Gilbert 	unsigned long iflags;
342338d5c833SDouglas Gilbert 	int ret;
3424d467d31fSDouglas Gilbert 	int retval = 0;
342538d5c833SDouglas Gilbert 
3426d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
342738d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
342838d5c833SDouglas Gilbert 	if (0 == num)
342938d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
34308475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
343138d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
343238d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
343338d5c833SDouglas Gilbert 		return check_condition_result;
343438d5c833SDouglas Gilbert 	}
34358475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
34368475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
343738d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
343838d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
343938d5c833SDouglas Gilbert 			    "to DIF device\n");
344038d5c833SDouglas Gilbert 
344138d5c833SDouglas Gilbert 	/* inline check_device_access_params() */
344238d5c833SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
344338d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
344438d5c833SDouglas Gilbert 		return check_condition_result;
344538d5c833SDouglas Gilbert 	}
344638d5c833SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
344738d5c833SDouglas Gilbert 	if (num > sdebug_store_sectors) {
344838d5c833SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
344938d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
345038d5c833SDouglas Gilbert 		return check_condition_result;
345138d5c833SDouglas Gilbert 	}
3452d467d31fSDouglas Gilbert 	dnum = 2 * num;
34536396bb22SKees Cook 	arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
3454d467d31fSDouglas Gilbert 	if (NULL == arr) {
3455d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3456d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3457d467d31fSDouglas Gilbert 		return check_condition_result;
3458d467d31fSDouglas Gilbert 	}
345938d5c833SDouglas Gilbert 
346038d5c833SDouglas Gilbert 	write_lock_irqsave(&atomic_rw, iflags);
346138d5c833SDouglas Gilbert 
346238d5c833SDouglas Gilbert 	/* trick do_device_access() to fetch both compare and write buffers
346338d5c833SDouglas Gilbert 	 * from data-in into arr. Safe (atomic) since write_lock held. */
346438d5c833SDouglas Gilbert 	fake_storep_hold = fake_storep;
346538d5c833SDouglas Gilbert 	fake_storep = arr;
34660a7e69c7SDouglas Gilbert 	ret = do_device_access(scp, 0, 0, dnum, true);
346738d5c833SDouglas Gilbert 	fake_storep = fake_storep_hold;
346838d5c833SDouglas Gilbert 	if (ret == -1) {
3469d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3470d467d31fSDouglas Gilbert 		goto cleanup;
3471773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
347238d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
347338d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
347438d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
347538d5c833SDouglas Gilbert 	if (!comp_write_worker(lba, num, arr)) {
347638d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3477d467d31fSDouglas Gilbert 		retval = check_condition_result;
3478d467d31fSDouglas Gilbert 		goto cleanup;
347938d5c833SDouglas Gilbert 	}
348038d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
348138d5c833SDouglas Gilbert 		map_region(lba, num);
3482d467d31fSDouglas Gilbert cleanup:
348338d5c833SDouglas Gilbert 	write_unlock_irqrestore(&atomic_rw, iflags);
3484d467d31fSDouglas Gilbert 	kfree(arr);
3485d467d31fSDouglas Gilbert 	return retval;
348638d5c833SDouglas Gilbert }
348738d5c833SDouglas Gilbert 
348844d92694SMartin K. Petersen struct unmap_block_desc {
348944d92694SMartin K. Petersen 	__be64	lba;
349044d92694SMartin K. Petersen 	__be32	blocks;
349144d92694SMartin K. Petersen 	__be32	__reserved;
349244d92694SMartin K. Petersen };
349344d92694SMartin K. Petersen 
3494fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
349544d92694SMartin K. Petersen {
349644d92694SMartin K. Petersen 	unsigned char *buf;
349744d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
349844d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
349944d92694SMartin K. Petersen 	int ret;
35006c78cc06SAkinobu Mita 	unsigned long iflags;
350144d92694SMartin K. Petersen 
350244d92694SMartin K. Petersen 
3503c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3504c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3505c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3506c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
350744d92694SMartin K. Petersen 
350844d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3509773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3510c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
351144d92694SMartin K. Petersen 		return check_condition_result;
3512c2248fc9SDouglas Gilbert 	}
351344d92694SMartin K. Petersen 
3514b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3515c2248fc9SDouglas Gilbert 	if (!buf) {
3516c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3517c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3518c2248fc9SDouglas Gilbert 		return check_condition_result;
3519c2248fc9SDouglas Gilbert 	}
3520c2248fc9SDouglas Gilbert 
3521c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
352244d92694SMartin K. Petersen 
352344d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
352444d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
352544d92694SMartin K. Petersen 
352644d92694SMartin K. Petersen 	desc = (void *)&buf[8];
352744d92694SMartin K. Petersen 
35286c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
35296c78cc06SAkinobu Mita 
353044d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
353144d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
353244d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
353344d92694SMartin K. Petersen 
3534c2248fc9SDouglas Gilbert 		ret = check_device_access_params(scp, lba, num);
353544d92694SMartin K. Petersen 		if (ret)
353644d92694SMartin K. Petersen 			goto out;
353744d92694SMartin K. Petersen 
353844d92694SMartin K. Petersen 		unmap_region(lba, num);
353944d92694SMartin K. Petersen 	}
354044d92694SMartin K. Petersen 
354144d92694SMartin K. Petersen 	ret = 0;
354244d92694SMartin K. Petersen 
354344d92694SMartin K. Petersen out:
35446c78cc06SAkinobu Mita 	write_unlock_irqrestore(&atomic_rw, iflags);
354544d92694SMartin K. Petersen 	kfree(buf);
354644d92694SMartin K. Petersen 
354744d92694SMartin K. Petersen 	return ret;
354844d92694SMartin K. Petersen }
354944d92694SMartin K. Petersen 
355044d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
355144d92694SMartin K. Petersen 
3552fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
3553fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
355444d92694SMartin K. Petersen {
3555c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3556c2248fc9SDouglas Gilbert 	u64 lba;
3557c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
3558c2248fc9SDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
355944d92694SMartin K. Petersen 	int ret;
356044d92694SMartin K. Petersen 
3561c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3562c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
356344d92694SMartin K. Petersen 
356444d92694SMartin K. Petersen 	if (alloc_len < 24)
356544d92694SMartin K. Petersen 		return 0;
356644d92694SMartin K. Petersen 
3567c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, 1);
356844d92694SMartin K. Petersen 	if (ret)
356944d92694SMartin K. Petersen 		return ret;
357044d92694SMartin K. Petersen 
3571c2248fc9SDouglas Gilbert 	if (scsi_debug_lbp())
357244d92694SMartin K. Petersen 		mapped = map_state(lba, &num);
3573c2248fc9SDouglas Gilbert 	else {
3574c2248fc9SDouglas Gilbert 		mapped = 1;
3575c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
3576c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
3577c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
3578c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
3579c2248fc9SDouglas Gilbert 		else
3580c2248fc9SDouglas Gilbert 			num = 0xffffffff;
3581c2248fc9SDouglas Gilbert 	}
358244d92694SMartin K. Petersen 
358344d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
3584c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
3585c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
3586c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
3587c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
358844d92694SMartin K. Petersen 
3589c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
359044d92694SMartin K. Petersen }
359144d92694SMartin K. Petersen 
359280c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp,
359380c49563SDouglas Gilbert 			   struct sdebug_dev_info *devip)
359480c49563SDouglas Gilbert {
35954f2c8bf6SDouglas Gilbert 	int res = 0;
359680c49563SDouglas Gilbert 	u64 lba;
359780c49563SDouglas Gilbert 	u32 num_blocks;
359880c49563SDouglas Gilbert 	u8 *cmd = scp->cmnd;
359980c49563SDouglas Gilbert 
360080c49563SDouglas Gilbert 	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
360180c49563SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
360280c49563SDouglas Gilbert 		num_blocks = get_unaligned_be16(cmd + 7);
360380c49563SDouglas Gilbert 	} else {				/* SYNCHRONIZE_CACHE(16) */
360480c49563SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
360580c49563SDouglas Gilbert 		num_blocks = get_unaligned_be32(cmd + 10);
360680c49563SDouglas Gilbert 	}
360780c49563SDouglas Gilbert 	if (lba + num_blocks > sdebug_capacity) {
360880c49563SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
360980c49563SDouglas Gilbert 		return check_condition_result;
361080c49563SDouglas Gilbert 	}
36114f2c8bf6SDouglas Gilbert 	if (!write_since_sync || cmd[1] & 0x2)
36124f2c8bf6SDouglas Gilbert 		res = SDEG_RES_IMMED_MASK;
36134f2c8bf6SDouglas Gilbert 	else		/* delay if write_since_sync and IMMED clear */
36144f2c8bf6SDouglas Gilbert 		write_since_sync = false;
36154f2c8bf6SDouglas Gilbert 	return res;
361680c49563SDouglas Gilbert }
361780c49563SDouglas Gilbert 
3618fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
3619fb0cc8d1SDouglas Gilbert 
36208d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
36218d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
36228d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
36238d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
36248d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
36258d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
36268d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
36278d039e22SDouglas Gilbert  */
36281da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
36291da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
36301da177e4SLinus Torvalds {
363101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
36328d039e22SDouglas Gilbert 	unsigned int alloc_len;
36338d039e22SDouglas Gilbert 	unsigned char select_report;
36348d039e22SDouglas Gilbert 	u64 lun;
36358d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
3636fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
36378d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
36388d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
36398d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
36408d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
3641fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
3642fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
3643fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
36441da177e4SLinus Torvalds 
364519c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
36468d039e22SDouglas Gilbert 
36478d039e22SDouglas Gilbert 	select_report = cmd[2];
36488d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
36498d039e22SDouglas Gilbert 
36508d039e22SDouglas Gilbert 	if (alloc_len < 4) {
36518d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
36528d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
36531da177e4SLinus Torvalds 		return check_condition_result;
36541da177e4SLinus Torvalds 	}
36558d039e22SDouglas Gilbert 
36568d039e22SDouglas Gilbert 	switch (select_report) {
36578d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
3658773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
36598d039e22SDouglas Gilbert 		wlun_cnt = 0;
36608d039e22SDouglas Gilbert 		break;
36618d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
3662c65b1445SDouglas Gilbert 		lun_cnt = 0;
36638d039e22SDouglas Gilbert 		wlun_cnt = 1;
36648d039e22SDouglas Gilbert 		break;
36658d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
36668d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
36678d039e22SDouglas Gilbert 		wlun_cnt = 1;
36688d039e22SDouglas Gilbert 		break;
36698d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
36708d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
36718d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
36728d039e22SDouglas Gilbert 	default:
36738d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
36748d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
36758d039e22SDouglas Gilbert 		return check_condition_result;
36768d039e22SDouglas Gilbert 	}
36778d039e22SDouglas Gilbert 
36788d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
3679c65b1445SDouglas Gilbert 		--lun_cnt;
36808d039e22SDouglas Gilbert 
36818d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
3682fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
3683fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
36848d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
36858d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
36868d039e22SDouglas Gilbert 
3687fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
36888d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
3689fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3690fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
3691fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
3692fb0cc8d1SDouglas Gilbert 		if (k == 0) {
3693fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
3694fb0cc8d1SDouglas Gilbert 			++lun_p;
3695fb0cc8d1SDouglas Gilbert 			j = 1;
3696fb0cc8d1SDouglas Gilbert 		}
3697fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3698fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3699fb0cc8d1SDouglas Gilbert 				break;
3700fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
3701fb0cc8d1SDouglas Gilbert 		}
3702fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
3703fb0cc8d1SDouglas Gilbert 			break;
3704fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
3705fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3706fb0cc8d1SDouglas Gilbert 		if (res)
3707fb0cc8d1SDouglas Gilbert 			return res;
3708fb0cc8d1SDouglas Gilbert 		off_rsp += n;
3709fb0cc8d1SDouglas Gilbert 	}
3710fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
3711fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3712fb0cc8d1SDouglas Gilbert 		++j;
3713fb0cc8d1SDouglas Gilbert 	}
3714fb0cc8d1SDouglas Gilbert 	if (j > 0)
3715fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
37168d039e22SDouglas Gilbert 	return res;
37171da177e4SLinus Torvalds }
37181da177e4SLinus Torvalds 
3719c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3720c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
3721c639d14eSFUJITA Tomonori {
3722be4e11beSAkinobu Mita 	int j;
3723c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
3724c639d14eSFUJITA Tomonori 	unsigned int offset;
3725c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
3726be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3727c639d14eSFUJITA Tomonori 
3728c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
3729b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3730c5af0db9SAkinobu Mita 	if (!buf) {
373122017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
373222017ed2SDouglas Gilbert 				INSUFF_RES_ASCQ);
3733c5af0db9SAkinobu Mita 		return check_condition_result;
3734c5af0db9SAkinobu Mita 	}
3735c639d14eSFUJITA Tomonori 
373621a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
3737c639d14eSFUJITA Tomonori 
3738c639d14eSFUJITA Tomonori 	offset = 0;
3739be4e11beSAkinobu Mita 	sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3740be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_TO_SG);
3741c639d14eSFUJITA Tomonori 
3742be4e11beSAkinobu Mita 	while (sg_miter_next(&miter)) {
3743be4e11beSAkinobu Mita 		kaddr = miter.addr;
3744be4e11beSAkinobu Mita 		for (j = 0; j < miter.length; j++)
3745be4e11beSAkinobu Mita 			*(kaddr + j) ^= *(buf + offset + j);
3746c639d14eSFUJITA Tomonori 
3747be4e11beSAkinobu Mita 		offset += miter.length;
3748c639d14eSFUJITA Tomonori 	}
3749be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3750c639d14eSFUJITA Tomonori 	kfree(buf);
3751c639d14eSFUJITA Tomonori 
3752be4e11beSAkinobu Mita 	return 0;
3753c639d14eSFUJITA Tomonori }
3754c639d14eSFUJITA Tomonori 
3755fd32119bSDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3756fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
3757c2248fc9SDouglas Gilbert {
3758c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3759c2248fc9SDouglas Gilbert 	u64 lba;
3760c2248fc9SDouglas Gilbert 	u32 num;
3761c2248fc9SDouglas Gilbert 	int errsts;
3762c2248fc9SDouglas Gilbert 
3763c2248fc9SDouglas Gilbert 	if (!scsi_bidi_cmnd(scp)) {
3764c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3765c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3766c2248fc9SDouglas Gilbert 		return check_condition_result;
3767c2248fc9SDouglas Gilbert 	}
3768c2248fc9SDouglas Gilbert 	errsts = resp_read_dt0(scp, devip);
3769c2248fc9SDouglas Gilbert 	if (errsts)
3770c2248fc9SDouglas Gilbert 		return errsts;
3771c2248fc9SDouglas Gilbert 	if (!(cmd[1] & 0x4)) {		/* DISABLE_WRITE is not set */
3772c2248fc9SDouglas Gilbert 		errsts = resp_write_dt0(scp, devip);
3773c2248fc9SDouglas Gilbert 		if (errsts)
3774c2248fc9SDouglas Gilbert 			return errsts;
3775c2248fc9SDouglas Gilbert 	}
3776c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3777c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3778c2248fc9SDouglas Gilbert 	return resp_xdwriteread(scp, lba, num, devip);
3779c2248fc9SDouglas Gilbert }
3780c2248fc9SDouglas Gilbert 
3781c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3782c4837394SDouglas Gilbert {
3783c4837394SDouglas Gilbert 	u32 tag = blk_mq_unique_tag(cmnd->request);
3784c4837394SDouglas Gilbert 	u16 hwq = blk_mq_unique_tag_to_hwq(tag);
3785c4837394SDouglas Gilbert 
3786458df78bSBart Van Assche 	pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
3787458df78bSBart Van Assche 	if (WARN_ON_ONCE(hwq >= submit_queues))
3788458df78bSBart Van Assche 		hwq = 0;
3789458df78bSBart Van Assche 	return sdebug_q_arr + hwq;
3790c4837394SDouglas Gilbert }
3791c4837394SDouglas Gilbert 
3792c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
3793fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
37941da177e4SLinus Torvalds {
3795c4837394SDouglas Gilbert 	int qc_idx;
3796cbf67842SDouglas Gilbert 	int retiring = 0;
37971da177e4SLinus Torvalds 	unsigned long iflags;
3798c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3799cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3800cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
3801cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
38021da177e4SLinus Torvalds 
380310bde980SDouglas Gilbert 	sd_dp->defer_t = SDEB_DEFER_NONE;
3804c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
3805c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
3806c4837394SDouglas Gilbert 	if (sdebug_statistics) {
3807cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
3808c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3809c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
3810c4837394SDouglas Gilbert 	}
3811c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3812c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
38131da177e4SLinus Torvalds 		return;
38141da177e4SLinus Torvalds 	}
3815c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
3816c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
3817cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
3818b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
3819c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3820c4837394SDouglas Gilbert 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3821c4837394SDouglas Gilbert 		       sd_dp->sqa_idx, qc_idx);
38221da177e4SLinus Torvalds 		return;
38231da177e4SLinus Torvalds 	}
3824cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
3825f46eb0e9SDouglas Gilbert 	if (likely(devip))
3826cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
3827cbf67842SDouglas Gilbert 	else
3828c1287970STomas Winkler 		pr_err("devip=NULL\n");
3829f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
3830cbf67842SDouglas Gilbert 		retiring = 1;
3831cbf67842SDouglas Gilbert 
3832cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
3833c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3834c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3835c1287970STomas Winkler 		pr_err("Unexpected completion\n");
3836cbf67842SDouglas Gilbert 		return;
38371da177e4SLinus Torvalds 	}
38381da177e4SLinus Torvalds 
3839cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
3840cbf67842SDouglas Gilbert 		int k, retval;
3841cbf67842SDouglas Gilbert 
3842cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
3843c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
3844c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3845c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
3846cbf67842SDouglas Gilbert 			return;
3847cbf67842SDouglas Gilbert 		}
3848c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
3849773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
3850cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3851cbf67842SDouglas Gilbert 		else
3852cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
3853cbf67842SDouglas Gilbert 	}
3854c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3855cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
3856cbf67842SDouglas Gilbert }
3857cbf67842SDouglas Gilbert 
3858cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
3859fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
3860cbf67842SDouglas Gilbert {
3861a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3862a10bc12aSDouglas Gilbert 						  hrt);
3863a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3864cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
3865cbf67842SDouglas Gilbert }
38661da177e4SLinus Torvalds 
3867a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
3868fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
3869a10bc12aSDouglas Gilbert {
3870a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3871a10bc12aSDouglas Gilbert 						  ew.work);
3872a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3873a10bc12aSDouglas Gilbert }
3874a10bc12aSDouglas Gilbert 
387509ba24c1SDouglas Gilbert static bool got_shared_uuid;
3876bf476433SChristoph Hellwig static uuid_t shared_uuid;
387709ba24c1SDouglas Gilbert 
3878fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
3879fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
38805cb2fc06SFUJITA Tomonori {
38815cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
38825cb2fc06SFUJITA Tomonori 
38835cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
38845cb2fc06SFUJITA Tomonori 	if (devip) {
388509ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
3886bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
388709ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
388809ba24c1SDouglas Gilbert 			if (got_shared_uuid)
388909ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
389009ba24c1SDouglas Gilbert 			else {
3891bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
389209ba24c1SDouglas Gilbert 				got_shared_uuid = true;
389309ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
389409ba24c1SDouglas Gilbert 			}
389509ba24c1SDouglas Gilbert 		}
38965cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
38975cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
38985cb2fc06SFUJITA Tomonori 	}
38995cb2fc06SFUJITA Tomonori 	return devip;
39005cb2fc06SFUJITA Tomonori }
39015cb2fc06SFUJITA Tomonori 
3902f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
39031da177e4SLinus Torvalds {
39041da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
39051da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
3906f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
39071da177e4SLinus Torvalds 
3908d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
39091da177e4SLinus Torvalds 	if (!sdbg_host) {
3910c1287970STomas Winkler 		pr_err("Host info NULL\n");
39111da177e4SLinus Torvalds 		return NULL;
39121da177e4SLinus Torvalds 	}
39131da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
39141da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
39151da177e4SLinus Torvalds 		    (devip->target == sdev->id) &&
39161da177e4SLinus Torvalds 		    (devip->lun == sdev->lun))
39171da177e4SLinus Torvalds 			return devip;
39181da177e4SLinus Torvalds 		else {
39191da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
39201da177e4SLinus Torvalds 				open_devip = devip;
39211da177e4SLinus Torvalds 		}
39221da177e4SLinus Torvalds 	}
39235cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
39245cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
39255cb2fc06SFUJITA Tomonori 		if (!open_devip) {
3926c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
39271da177e4SLinus Torvalds 			return NULL;
39281da177e4SLinus Torvalds 		}
39291da177e4SLinus Torvalds 	}
3930a75869d1SFUJITA Tomonori 
39311da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
39321da177e4SLinus Torvalds 	open_devip->target = sdev->id;
39331da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
39341da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
3935cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
3936cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
3937c2248fc9SDouglas Gilbert 	open_devip->used = true;
39381da177e4SLinus Torvalds 	return open_devip;
39391da177e4SLinus Torvalds }
39401da177e4SLinus Torvalds 
39418dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
39421da177e4SLinus Torvalds {
3943773642d9SDouglas Gilbert 	if (sdebug_verbose)
3944c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
39458dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
39468b904b5bSBart Van Assche 	blk_queue_flag_set(QUEUE_FLAG_BIDI, sdp->request_queue);
39478dea0d02SFUJITA Tomonori 	return 0;
39488dea0d02SFUJITA Tomonori }
39491da177e4SLinus Torvalds 
39508dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
39518dea0d02SFUJITA Tomonori {
3952f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
3953f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
3954a34c4e98SFUJITA Tomonori 
3955773642d9SDouglas Gilbert 	if (sdebug_verbose)
3956c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
39578dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3958b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3959b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3960b01f6f83SDouglas Gilbert 	if (devip == NULL) {
3961f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
3962b01f6f83SDouglas Gilbert 		if (devip == NULL)
39638dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
3964f46eb0e9SDouglas Gilbert 	}
3965c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
39666bb5e6e7SAkinobu Mita 	blk_queue_max_segment_size(sdp->request_queue, -1U);
3967773642d9SDouglas Gilbert 	if (sdebug_no_uld)
396878d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
39699b760fd8SDouglas Gilbert 	config_cdb_len(sdp);
39708dea0d02SFUJITA Tomonori 	return 0;
39718dea0d02SFUJITA Tomonori }
39728dea0d02SFUJITA Tomonori 
39738dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
39748dea0d02SFUJITA Tomonori {
39758dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
39768dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
39778dea0d02SFUJITA Tomonori 
3978773642d9SDouglas Gilbert 	if (sdebug_verbose)
3979c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
39808dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
39818dea0d02SFUJITA Tomonori 	if (devip) {
398225985edcSLucas De Marchi 		/* make this slot available for re-use */
3983c2248fc9SDouglas Gilbert 		devip->used = false;
39848dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
39858dea0d02SFUJITA Tomonori 	}
39868dea0d02SFUJITA Tomonori }
39878dea0d02SFUJITA Tomonori 
398810bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp,
398910bde980SDouglas Gilbert 			   enum sdeb_defer_type defer_t)
3990c4837394SDouglas Gilbert {
3991c4837394SDouglas Gilbert 	if (!sd_dp)
3992c4837394SDouglas Gilbert 		return;
399310bde980SDouglas Gilbert 	if (defer_t == SDEB_DEFER_HRT)
3994c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
399510bde980SDouglas Gilbert 	else if (defer_t == SDEB_DEFER_WQ)
3996c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
3997c4837394SDouglas Gilbert }
3998c4837394SDouglas Gilbert 
3999a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
4000a10bc12aSDouglas Gilbert    returns false */
4001a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
40028dea0d02SFUJITA Tomonori {
40038dea0d02SFUJITA Tomonori 	unsigned long iflags;
4004c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
400510bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
4006c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
40078dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
4008cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4009a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
40108dea0d02SFUJITA Tomonori 
4011c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4012c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
4013773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
4014cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
4015cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
4016cbf67842SDouglas Gilbert 			qmax = r_qmax;
4017cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
4018c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
4019c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
4020a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
4021a10bc12aSDouglas Gilbert 					continue;
4022c4837394SDouglas Gilbert 				/* found */
4023db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
4024db525fceSDouglas Gilbert 						cmnd->device->hostdata;
4025db525fceSDouglas Gilbert 				if (devip)
4026db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
4027db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
4028a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
402910bde980SDouglas Gilbert 				if (sd_dp) {
403010bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
403110bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
403210bde980SDouglas Gilbert 				} else
403310bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
4034c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
403510bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
4036c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
4037a10bc12aSDouglas Gilbert 				return true;
40388dea0d02SFUJITA Tomonori 			}
4039cbf67842SDouglas Gilbert 		}
4040c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4041c4837394SDouglas Gilbert 	}
4042a10bc12aSDouglas Gilbert 	return false;
40438dea0d02SFUJITA Tomonori }
40448dea0d02SFUJITA Tomonori 
4045a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
40468dea0d02SFUJITA Tomonori static void stop_all_queued(void)
40478dea0d02SFUJITA Tomonori {
40488dea0d02SFUJITA Tomonori 	unsigned long iflags;
4049c4837394SDouglas Gilbert 	int j, k;
405010bde980SDouglas Gilbert 	enum sdeb_defer_type l_defer_t;
4051c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
40528dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
4053cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4054a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
40558dea0d02SFUJITA Tomonori 
4056c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4057c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
4058c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4059c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
4060c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
4061c4837394SDouglas Gilbert 				if (sqcp->a_cmnd == NULL)
4062a10bc12aSDouglas Gilbert 					continue;
4063db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
4064db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
4065db525fceSDouglas Gilbert 				if (devip)
4066db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
4067db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
4068a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
406910bde980SDouglas Gilbert 				if (sd_dp) {
407010bde980SDouglas Gilbert 					l_defer_t = sd_dp->defer_t;
407110bde980SDouglas Gilbert 					sd_dp->defer_t = SDEB_DEFER_NONE;
407210bde980SDouglas Gilbert 				} else
407310bde980SDouglas Gilbert 					l_defer_t = SDEB_DEFER_NONE;
4074c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
407510bde980SDouglas Gilbert 				stop_qc_helper(sd_dp, l_defer_t);
4076c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
4077c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
40788dea0d02SFUJITA Tomonori 			}
40798dea0d02SFUJITA Tomonori 		}
4080c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4081c4837394SDouglas Gilbert 	}
4082cbf67842SDouglas Gilbert }
4083cbf67842SDouglas Gilbert 
4084cbf67842SDouglas Gilbert /* Free queued command memory on heap */
4085cbf67842SDouglas Gilbert static void free_all_queued(void)
4086cbf67842SDouglas Gilbert {
4087c4837394SDouglas Gilbert 	int j, k;
4088c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4089cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4090cbf67842SDouglas Gilbert 
4091c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4092c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4093c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
4094a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
4095a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
4096cbf67842SDouglas Gilbert 		}
40971da177e4SLinus Torvalds 	}
4098c4837394SDouglas Gilbert }
40991da177e4SLinus Torvalds 
41001da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
41011da177e4SLinus Torvalds {
4102a10bc12aSDouglas Gilbert 	bool ok;
4103a10bc12aSDouglas Gilbert 
41041da177e4SLinus Torvalds 	++num_aborts;
4105cbf67842SDouglas Gilbert 	if (SCpnt) {
4106a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
4107a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
4108a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
4109a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
4110a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
4111cbf67842SDouglas Gilbert 	}
41121da177e4SLinus Torvalds 	return SUCCESS;
41131da177e4SLinus Torvalds }
41141da177e4SLinus Torvalds 
41151da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
41161da177e4SLinus Torvalds {
41171da177e4SLinus Torvalds 	++num_dev_resets;
4118cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
4119cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
4120f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
4121f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
4122cbf67842SDouglas Gilbert 
4123773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
4124cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
41251da177e4SLinus Torvalds 		if (devip)
4126cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
41271da177e4SLinus Torvalds 	}
41281da177e4SLinus Torvalds 	return SUCCESS;
41291da177e4SLinus Torvalds }
41301da177e4SLinus Torvalds 
4131cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
4132cbf67842SDouglas Gilbert {
4133cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
4134cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4135cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
4136cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
4137cbf67842SDouglas Gilbert 	int k = 0;
4138cbf67842SDouglas Gilbert 
4139cbf67842SDouglas Gilbert 	++num_target_resets;
4140cbf67842SDouglas Gilbert 	if (!SCpnt)
4141cbf67842SDouglas Gilbert 		goto lie;
4142cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
4143cbf67842SDouglas Gilbert 	if (!sdp)
4144cbf67842SDouglas Gilbert 		goto lie;
4145773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
4146cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4147cbf67842SDouglas Gilbert 	hp = sdp->host;
4148cbf67842SDouglas Gilbert 	if (!hp)
4149cbf67842SDouglas Gilbert 		goto lie;
4150cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
4151cbf67842SDouglas Gilbert 	if (sdbg_host) {
4152cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
4153cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
4154cbf67842SDouglas Gilbert 				    dev_list)
4155cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
4156cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4157cbf67842SDouglas Gilbert 				++k;
4158cbf67842SDouglas Gilbert 			}
4159cbf67842SDouglas Gilbert 	}
4160773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
4161cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4162cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
4163cbf67842SDouglas Gilbert lie:
4164cbf67842SDouglas Gilbert 	return SUCCESS;
4165cbf67842SDouglas Gilbert }
4166cbf67842SDouglas Gilbert 
41671da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
41681da177e4SLinus Torvalds {
41691da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
4170cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
41711da177e4SLinus Torvalds 	struct scsi_device *sdp;
41721da177e4SLinus Torvalds 	struct Scsi_Host *hp;
4173cbf67842SDouglas Gilbert 	int k = 0;
41741da177e4SLinus Torvalds 
41751da177e4SLinus Torvalds 	++num_bus_resets;
4176cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
4177cbf67842SDouglas Gilbert 		goto lie;
4178cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
4179773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
4180cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4181cbf67842SDouglas Gilbert 	hp = sdp->host;
4182cbf67842SDouglas Gilbert 	if (hp) {
4183d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
41841da177e4SLinus Torvalds 		if (sdbg_host) {
4185cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
41861da177e4SLinus Torvalds 					    &sdbg_host->dev_info_list,
4187cbf67842SDouglas Gilbert 					    dev_list) {
4188cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4189cbf67842SDouglas Gilbert 				++k;
41901da177e4SLinus Torvalds 			}
41911da177e4SLinus Torvalds 		}
4192cbf67842SDouglas Gilbert 	}
4193773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
4194cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4195cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
4196cbf67842SDouglas Gilbert lie:
41971da177e4SLinus Torvalds 	return SUCCESS;
41981da177e4SLinus Torvalds }
41991da177e4SLinus Torvalds 
42001da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
42011da177e4SLinus Torvalds {
42021da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
4203cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4204cbf67842SDouglas Gilbert 	int k = 0;
42051da177e4SLinus Torvalds 
42061da177e4SLinus Torvalds 	++num_host_resets;
4207773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
4208cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
42091da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
42101da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
4211cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
4212cbf67842SDouglas Gilbert 				    dev_list) {
4213cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4214cbf67842SDouglas Gilbert 			++k;
4215cbf67842SDouglas Gilbert 		}
42161da177e4SLinus Torvalds 	}
42171da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
42181da177e4SLinus Torvalds 	stop_all_queued();
4219773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
4220cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
4221cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
42221da177e4SLinus Torvalds 	return SUCCESS;
42231da177e4SLinus Torvalds }
42241da177e4SLinus Torvalds 
4225f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
42265f2578e5SFUJITA Tomonori 				      unsigned long store_size)
42271da177e4SLinus Torvalds {
42281da177e4SLinus Torvalds 	struct partition *pp;
42291da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
42301da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
42311da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
42321da177e4SLinus Torvalds 
42331da177e4SLinus Torvalds 	/* assume partition table already zeroed */
4234773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
42351da177e4SLinus Torvalds 		return;
4236773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
4237773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
4238c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
42391da177e4SLinus Torvalds 	}
4240c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
42411da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
4242773642d9SDouglas Gilbert 			   / sdebug_num_parts;
42431da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
42441da177e4SLinus Torvalds 	starts[0] = sdebug_sectors_per;
4245773642d9SDouglas Gilbert 	for (k = 1; k < sdebug_num_parts; ++k)
42461da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
42471da177e4SLinus Torvalds 			    * heads_by_sects;
4248773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
4249773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
42501da177e4SLinus Torvalds 
42511da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
42521da177e4SLinus Torvalds 	ramp[511] = 0xAA;
42531da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
42541da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
42551da177e4SLinus Torvalds 		start_sec = starts[k];
42561da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
42571da177e4SLinus Torvalds 		pp->boot_ind = 0;
42581da177e4SLinus Torvalds 
42591da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
42601da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
42611da177e4SLinus Torvalds 			   / sdebug_sectors_per;
42621da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
42631da177e4SLinus Torvalds 
42641da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
42651da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
42661da177e4SLinus Torvalds 			       / sdebug_sectors_per;
42671da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
42681da177e4SLinus Torvalds 
4269150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
4270150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
42711da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
42721da177e4SLinus Torvalds 	}
42731da177e4SLinus Torvalds }
42741da177e4SLinus Torvalds 
4275c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block)
4276c4837394SDouglas Gilbert {
4277c4837394SDouglas Gilbert 	int j;
4278c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4279c4837394SDouglas Gilbert 
4280c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
4281c4837394SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)block);
4282c4837394SDouglas Gilbert }
4283c4837394SDouglas Gilbert 
4284c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
4285c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
4286c4837394SDouglas Gilbert  */
4287c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
4288c4837394SDouglas Gilbert {
4289c4837394SDouglas Gilbert 	int count, modulo;
4290c4837394SDouglas Gilbert 
4291c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
4292c4837394SDouglas Gilbert 	if (modulo < 2)
4293c4837394SDouglas Gilbert 		return;
4294c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
4295c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
4296c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
4297c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
4298c4837394SDouglas Gilbert }
4299c4837394SDouglas Gilbert 
4300c4837394SDouglas Gilbert static void clear_queue_stats(void)
4301c4837394SDouglas Gilbert {
4302c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
4303c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
4304c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
4305c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
4306c4837394SDouglas Gilbert }
4307c4837394SDouglas Gilbert 
4308c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp,
4309c4837394SDouglas Gilbert 			 struct sdebug_queued_cmd *sqcp)
4310c4837394SDouglas Gilbert {
4311f9ba7af8SMartin Wilck 	if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) {
4312f9ba7af8SMartin Wilck 		if (sdebug_every_nth > 0)
4313f9ba7af8SMartin Wilck 			sqcp->inj_recovered = sqcp->inj_transport
4314f9ba7af8SMartin Wilck 				= sqcp->inj_dif
4315f9ba7af8SMartin Wilck 				= sqcp->inj_dix = sqcp->inj_short = 0;
4316c4837394SDouglas Gilbert 		return;
4317f9ba7af8SMartin Wilck 	}
4318c4837394SDouglas Gilbert 	sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
4319c4837394SDouglas Gilbert 	sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
4320c4837394SDouglas Gilbert 	sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
4321c4837394SDouglas Gilbert 	sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
4322c4837394SDouglas Gilbert 	sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
43237ee6d1b4SBart Van Assche 	sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
4324c4837394SDouglas Gilbert }
4325c4837394SDouglas Gilbert 
4326c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
4327c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
4328c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
4329c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
4330c4837394SDouglas Gilbert  */
4331fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
4332f66b8517SMartin Wilck 			 int scsi_result,
4333f66b8517SMartin Wilck 			 int (*pfp)(struct scsi_cmnd *,
4334f66b8517SMartin Wilck 				    struct sdebug_dev_info *),
4335f66b8517SMartin Wilck 			 int delta_jiff, int ndelay)
43361da177e4SLinus Torvalds {
4337cbf67842SDouglas Gilbert 	unsigned long iflags;
4338cd62b7daSDouglas Gilbert 	int k, num_in_q, qdepth, inject;
4339c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4340c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4341299b6c07STomas Winkler 	struct scsi_device *sdp;
4342a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
43431da177e4SLinus Torvalds 
4344b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
4345b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
4346f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
4347f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
43481da177e4SLinus Torvalds 	}
4349299b6c07STomas Winkler 	sdp = cmnd->device;
4350299b6c07STomas Winkler 
4351cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
4352cd62b7daSDouglas Gilbert 		goto respond_in_thread;
43531da177e4SLinus Torvalds 
4354cd62b7daSDouglas Gilbert 	/* schedule the response at a later time if resources permit */
4355c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
4356c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
4357c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
4358c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4359c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
4360c4837394SDouglas Gilbert 	}
4361cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
4362cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
4363cbf67842SDouglas Gilbert 	inject = 0;
4364f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
4365cd62b7daSDouglas Gilbert 		if (scsi_result) {
4366c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4367cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4368cd62b7daSDouglas Gilbert 		} else
4369cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4370c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
4371773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4372f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
4373cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
4374cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
4375773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
4376cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
4377cbf67842SDouglas Gilbert 			inject = 1;
4378cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
43791da177e4SLinus Torvalds 		}
4380cbf67842SDouglas Gilbert 	}
4381cbf67842SDouglas Gilbert 
4382c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
4383f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
4384c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4385cd62b7daSDouglas Gilbert 		if (scsi_result)
4386cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4387773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
4388cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4389773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
4390cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
4391cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
4392773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
4393cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
4394cbf67842SDouglas Gilbert 						    "report: host busy"));
4395cd62b7daSDouglas Gilbert 		if (scsi_result)
4396cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4397cd62b7daSDouglas Gilbert 		else
4398cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
43991da177e4SLinus Torvalds 	}
4400c4837394SDouglas Gilbert 	__set_bit(k, sqp->in_use_bm);
4401cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
4402c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
44031da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
4404c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
4405a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
4406c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4407c4837394SDouglas Gilbert 	if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4408c4837394SDouglas Gilbert 		setup_inject(sqp, sqcp);
440910bde980SDouglas Gilbert 	if (sd_dp == NULL) {
441010bde980SDouglas Gilbert 		sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
441110bde980SDouglas Gilbert 		if (sd_dp == NULL)
441210bde980SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
441310bde980SDouglas Gilbert 	}
4414f66b8517SMartin Wilck 
4415f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
4416f66b8517SMartin Wilck 	if (cmnd->result & SDEG_RES_IMMED_MASK) {
4417f66b8517SMartin Wilck 		/*
4418f66b8517SMartin Wilck 		 * This is the F_DELAY_OVERR case. No delay.
4419f66b8517SMartin Wilck 		 */
4420f66b8517SMartin Wilck 		cmnd->result &= ~SDEG_RES_IMMED_MASK;
4421f66b8517SMartin Wilck 		delta_jiff = ndelay = 0;
4422f66b8517SMartin Wilck 	}
4423f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
4424f66b8517SMartin Wilck 		cmnd->result = scsi_result;
4425f66b8517SMartin Wilck 
4426f66b8517SMartin Wilck 	if (unlikely(sdebug_verbose && cmnd->result))
4427f66b8517SMartin Wilck 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4428f66b8517SMartin Wilck 			    __func__, cmnd->result);
4429f66b8517SMartin Wilck 
443010bde980SDouglas Gilbert 	if (delta_jiff > 0 || ndelay > 0) {
4431b333a819SDouglas Gilbert 		ktime_t kt;
4432cbf67842SDouglas Gilbert 
4433b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
443413f6b610SArnd Bergmann 			kt = ns_to_ktime((u64)delta_jiff * (NSEC_PER_SEC / HZ));
4435b333a819SDouglas Gilbert 		} else
443610bde980SDouglas Gilbert 			kt = ndelay;
443710bde980SDouglas Gilbert 		if (!sd_dp->init_hrt) {
443810bde980SDouglas Gilbert 			sd_dp->init_hrt = true;
4439a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4440a10bc12aSDouglas Gilbert 			hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
4441c4837394SDouglas Gilbert 				     HRTIMER_MODE_REL_PINNED);
4442a10bc12aSDouglas Gilbert 			sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
4443c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4444c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4445cbf67842SDouglas Gilbert 		}
4446c4837394SDouglas Gilbert 		if (sdebug_statistics)
4447c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
444810bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_HRT;
4449c4837394SDouglas Gilbert 		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4450c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
445110bde980SDouglas Gilbert 		if (!sd_dp->init_wq) {
445210bde980SDouglas Gilbert 			sd_dp->init_wq = true;
4453a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4454c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4455c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4456a10bc12aSDouglas Gilbert 			INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
4457cbf67842SDouglas Gilbert 		}
4458c4837394SDouglas Gilbert 		if (sdebug_statistics)
4459c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
446010bde980SDouglas Gilbert 		sd_dp->defer_t = SDEB_DEFER_WQ;
4461a10bc12aSDouglas Gilbert 		schedule_work(&sd_dp->ew.work);
4462cbf67842SDouglas Gilbert 	}
4463f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4464f46eb0e9SDouglas Gilbert 		     (scsi_result == device_qfull_result)))
4465cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4466cbf67842SDouglas Gilbert 			    "%s: num_in_q=%d +1, %s%s\n", __func__,
4467cbf67842SDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""),
4468cbf67842SDouglas Gilbert 			    "status: TASK SET FULL");
44691da177e4SLinus Torvalds 	return 0;
4470cd62b7daSDouglas Gilbert 
4471cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
4472f66b8517SMartin Wilck 	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
4473f66b8517SMartin Wilck 	cmnd->result &= ~SDEG_RES_IMMED_MASK;
4474f66b8517SMartin Wilck 	if (cmnd->result == 0 && scsi_result != 0)
4475cd62b7daSDouglas Gilbert 		cmnd->result = scsi_result;
4476cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
4477cd62b7daSDouglas Gilbert 	return 0;
44781da177e4SLinus Torvalds }
4479cbf67842SDouglas Gilbert 
448023183910SDouglas Gilbert /* Note: The following macros create attribute files in the
448123183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
448223183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
448323183910SDouglas Gilbert    as it can when the corresponding attribute in the
448423183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
448523183910SDouglas Gilbert  */
4486773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4487773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
44889b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
4489773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
4490c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
4491773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4492773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
4493773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
4494773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4495773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4496773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4497773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4498773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
4499e5203cf0SHannes Reinecke module_param_string(inq_vendor, sdebug_inq_vendor_id,
4500e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR);
4501e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
4502e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR);
4503e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
4504e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR);
4505773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4506773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4507773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4508773642d9SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4509773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4510773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4511773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4512d9da891aSLaurence Oberman module_param_named(medium_error_start, sdebug_medium_error_start, int, S_IRUGO | S_IWUSR);
4513d9da891aSLaurence Oberman module_param_named(medium_error_count, sdebug_medium_error_count, int, S_IRUGO | S_IWUSR);
4514773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4515773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4516773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4517773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4518773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4519773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4520773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4521773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
452286e6828aSLukas Herbolt module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
4523773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4524773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4525773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4526773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
4527c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
4528773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
4529c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
4530773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4531773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4532773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4533773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4534773642d9SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
453509ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
4536773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
453723183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
4538773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
45395b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
45401da177e4SLinus Torvalds 
45411da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
45421da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
45431da177e4SLinus Torvalds MODULE_LICENSE("GPL");
4544b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
45451da177e4SLinus Torvalds 
45461da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
45475b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
45489b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
45490759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
4550cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
4551c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
45525b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
45535b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
4554c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
4555beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
455623183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
45575b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
4558185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
4559e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
4560e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
45619b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
45629b760fd8SDouglas Gilbert 		 SDEBUG_VERSION "\")");
45635b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
45645b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
45655b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
4566760f3b03SDouglas Gilbert MODULE_PARM_DESC(lbprz,
4567760f3b03SDouglas Gilbert 	"on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
45685b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
4569c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
4570cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4571d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
4572d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
4573cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
4574c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
457578d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
45761da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
4577c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
457832c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
45796f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
45805b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
458186e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
45821da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
4583d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
4584760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
4585ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
4586c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
4587c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
4588c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
45895b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
45905b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
45916014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
45926014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
459309ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
459409ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
4595c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
45965b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
45975b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
45981da177e4SLinus Torvalds 
4599760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
4600760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
46011da177e4SLinus Torvalds 
46021da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp)
46031da177e4SLinus Torvalds {
4604c4837394SDouglas Gilbert 	int k;
4605c4837394SDouglas Gilbert 
4606760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4607760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
4608760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
4609c4837394SDouglas Gilbert 		return sdebug_info;
4610760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4611760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4612760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
4613760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
46141da177e4SLinus Torvalds 	return sdebug_info;
46151da177e4SLinus Torvalds }
46161da177e4SLinus Torvalds 
4617cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
4618fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4619fd32119bSDouglas Gilbert 				 int length)
46201da177e4SLinus Torvalds {
46211da177e4SLinus Torvalds 	char arr[16];
4622c8ed555aSAl Viro 	int opts;
46231da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
46241da177e4SLinus Torvalds 
46251da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
46261da177e4SLinus Torvalds 		return -EACCES;
46271da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
46281da177e4SLinus Torvalds 	arr[minLen] = '\0';
4629c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
46301da177e4SLinus Torvalds 		return -EINVAL;
4631773642d9SDouglas Gilbert 	sdebug_opts = opts;
4632773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4633773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4634773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
4635c4837394SDouglas Gilbert 		tweak_cmnd_count();
46361da177e4SLinus Torvalds 	return length;
46371da177e4SLinus Torvalds }
4638c8ed555aSAl Viro 
4639cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4640cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
4641cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
4642c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4643c8ed555aSAl Viro {
4644c4837394SDouglas Gilbert 	int f, j, l;
4645c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4646cbf67842SDouglas Gilbert 
4647c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4648c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
4649c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4650c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4651c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
4652c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4653c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4654c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
4655c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4656c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4657c4837394SDouglas Gilbert 		   num_aborts);
4658c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4659c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
4660c4837394SDouglas Gilbert 		   num_host_resets);
4661c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4662c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
4663458df78bSBart Van Assche 	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
4664458df78bSBart Van Assche 		   sdebug_statistics);
4665c4837394SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4666c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
4667c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
4668c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
4669c4837394SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf));
4670cbf67842SDouglas Gilbert 
4671c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
4672c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4673c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
4674c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4675773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
4676c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4677c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
4678c4837394SDouglas Gilbert 				   "first,last bits", f, l);
4679c4837394SDouglas Gilbert 		}
4680cbf67842SDouglas Gilbert 	}
4681c8ed555aSAl Viro 	return 0;
46821da177e4SLinus Torvalds }
46831da177e4SLinus Torvalds 
468482069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
46851da177e4SLinus Torvalds {
4686c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
46871da177e4SLinus Torvalds }
4688c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4689c4837394SDouglas Gilbert  * of delay is jiffies.
4690c4837394SDouglas Gilbert  */
469182069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
469282069379SAkinobu Mita 			   size_t count)
46931da177e4SLinus Torvalds {
4694c2206098SDouglas Gilbert 	int jdelay, res;
46951da177e4SLinus Torvalds 
4696b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
4697cbf67842SDouglas Gilbert 		res = count;
4698c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
4699c4837394SDouglas Gilbert 			int j, k;
4700c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4701cbf67842SDouglas Gilbert 
4702c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4703c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4704c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4705c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4706c4837394SDouglas Gilbert 						   sdebug_max_queue);
4707c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4708c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4709c4837394SDouglas Gilbert 					break;
4710c4837394SDouglas Gilbert 				}
4711c4837394SDouglas Gilbert 			}
4712c4837394SDouglas Gilbert 			if (res > 0) {
4713c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
4714773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
47151da177e4SLinus Torvalds 			}
4716c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4717cbf67842SDouglas Gilbert 		}
4718cbf67842SDouglas Gilbert 		return res;
47191da177e4SLinus Torvalds 	}
47201da177e4SLinus Torvalds 	return -EINVAL;
47211da177e4SLinus Torvalds }
472282069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
47231da177e4SLinus Torvalds 
4724cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4725cbf67842SDouglas Gilbert {
4726773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
4727cbf67842SDouglas Gilbert }
4728cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
4729c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
4730cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
4731cbf67842SDouglas Gilbert 			    size_t count)
4732cbf67842SDouglas Gilbert {
4733c4837394SDouglas Gilbert 	int ndelay, res;
4734cbf67842SDouglas Gilbert 
4735cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4736c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
4737cbf67842SDouglas Gilbert 		res = count;
4738773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
4739c4837394SDouglas Gilbert 			int j, k;
4740c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4741c4837394SDouglas Gilbert 
4742c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4743c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4744c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4745c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4746c4837394SDouglas Gilbert 						   sdebug_max_queue);
4747c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4748c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4749c4837394SDouglas Gilbert 					break;
4750c4837394SDouglas Gilbert 				}
4751c4837394SDouglas Gilbert 			}
4752c4837394SDouglas Gilbert 			if (res > 0) {
4753773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
4754c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
4755c2206098SDouglas Gilbert 							: DEF_JDELAY;
4756cbf67842SDouglas Gilbert 			}
4757c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4758cbf67842SDouglas Gilbert 		}
4759cbf67842SDouglas Gilbert 		return res;
4760cbf67842SDouglas Gilbert 	}
4761cbf67842SDouglas Gilbert 	return -EINVAL;
4762cbf67842SDouglas Gilbert }
4763cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
4764cbf67842SDouglas Gilbert 
476582069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
47661da177e4SLinus Torvalds {
4767773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
47681da177e4SLinus Torvalds }
47691da177e4SLinus Torvalds 
477082069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
477182069379SAkinobu Mita 			  size_t count)
47721da177e4SLinus Torvalds {
47731da177e4SLinus Torvalds 	int opts;
47741da177e4SLinus Torvalds 	char work[20];
47751da177e4SLinus Torvalds 
47769a051019SDouglas Gilbert 	if (sscanf(buf, "%10s", work) == 1) {
47779a051019SDouglas Gilbert 		if (strncasecmp(work, "0x", 2) == 0) {
47789a051019SDouglas Gilbert 			if (kstrtoint(work + 2, 16, &opts) == 0)
47791da177e4SLinus Torvalds 				goto opts_done;
47801da177e4SLinus Torvalds 		} else {
47819a051019SDouglas Gilbert 			if (kstrtoint(work, 10, &opts) == 0)
47821da177e4SLinus Torvalds 				goto opts_done;
47831da177e4SLinus Torvalds 		}
47841da177e4SLinus Torvalds 	}
47851da177e4SLinus Torvalds 	return -EINVAL;
47861da177e4SLinus Torvalds opts_done:
4787773642d9SDouglas Gilbert 	sdebug_opts = opts;
4788773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4789773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4790c4837394SDouglas Gilbert 	tweak_cmnd_count();
47911da177e4SLinus Torvalds 	return count;
47921da177e4SLinus Torvalds }
479382069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
47941da177e4SLinus Torvalds 
479582069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
47961da177e4SLinus Torvalds {
4797773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
47981da177e4SLinus Torvalds }
479982069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
480082069379SAkinobu Mita 			   size_t count)
48011da177e4SLinus Torvalds {
48021da177e4SLinus Torvalds 	int n;
48031da177e4SLinus Torvalds 
48041da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4805773642d9SDouglas Gilbert 		sdebug_ptype = n;
48061da177e4SLinus Torvalds 		return count;
48071da177e4SLinus Torvalds 	}
48081da177e4SLinus Torvalds 	return -EINVAL;
48091da177e4SLinus Torvalds }
481082069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
48111da177e4SLinus Torvalds 
481282069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
48131da177e4SLinus Torvalds {
4814773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
48151da177e4SLinus Torvalds }
481682069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
481782069379SAkinobu Mita 			    size_t count)
48181da177e4SLinus Torvalds {
48191da177e4SLinus Torvalds 	int n;
48201da177e4SLinus Torvalds 
48211da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4822773642d9SDouglas Gilbert 		sdebug_dsense = n;
48231da177e4SLinus Torvalds 		return count;
48241da177e4SLinus Torvalds 	}
48251da177e4SLinus Torvalds 	return -EINVAL;
48261da177e4SLinus Torvalds }
482782069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
48281da177e4SLinus Torvalds 
482982069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
483023183910SDouglas Gilbert {
4831773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
483223183910SDouglas Gilbert }
483382069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
483482069379SAkinobu Mita 			     size_t count)
483523183910SDouglas Gilbert {
483623183910SDouglas Gilbert 	int n;
483723183910SDouglas Gilbert 
483823183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4839cbf67842SDouglas Gilbert 		n = (n > 0);
4840773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
4841773642d9SDouglas Gilbert 		if (sdebug_fake_rw != n) {
4842cbf67842SDouglas Gilbert 			if ((0 == n) && (NULL == fake_storep)) {
4843cbf67842SDouglas Gilbert 				unsigned long sz =
4844773642d9SDouglas Gilbert 					(unsigned long)sdebug_dev_size_mb *
4845cbf67842SDouglas Gilbert 					1048576;
4846cbf67842SDouglas Gilbert 
4847cbf67842SDouglas Gilbert 				fake_storep = vmalloc(sz);
4848cbf67842SDouglas Gilbert 				if (NULL == fake_storep) {
4849c1287970STomas Winkler 					pr_err("out of memory, 9\n");
4850cbf67842SDouglas Gilbert 					return -ENOMEM;
4851cbf67842SDouglas Gilbert 				}
4852cbf67842SDouglas Gilbert 				memset(fake_storep, 0, sz);
4853cbf67842SDouglas Gilbert 			}
4854773642d9SDouglas Gilbert 			sdebug_fake_rw = n;
4855cbf67842SDouglas Gilbert 		}
485623183910SDouglas Gilbert 		return count;
485723183910SDouglas Gilbert 	}
485823183910SDouglas Gilbert 	return -EINVAL;
485923183910SDouglas Gilbert }
486082069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
486123183910SDouglas Gilbert 
486282069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
4863c65b1445SDouglas Gilbert {
4864773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
4865c65b1445SDouglas Gilbert }
486682069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
486782069379SAkinobu Mita 			      size_t count)
4868c65b1445SDouglas Gilbert {
4869c65b1445SDouglas Gilbert 	int n;
4870c65b1445SDouglas Gilbert 
4871c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4872773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
4873c65b1445SDouglas Gilbert 		return count;
4874c65b1445SDouglas Gilbert 	}
4875c65b1445SDouglas Gilbert 	return -EINVAL;
4876c65b1445SDouglas Gilbert }
487782069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
4878c65b1445SDouglas Gilbert 
487982069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
48801da177e4SLinus Torvalds {
4881773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
48821da177e4SLinus Torvalds }
488382069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
488482069379SAkinobu Mita 			      size_t count)
48851da177e4SLinus Torvalds {
48861da177e4SLinus Torvalds 	int n;
48871da177e4SLinus Torvalds 
48881da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4889773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
48901da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
48911da177e4SLinus Torvalds 		return count;
48921da177e4SLinus Torvalds 	}
48931da177e4SLinus Torvalds 	return -EINVAL;
48941da177e4SLinus Torvalds }
489582069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
48961da177e4SLinus Torvalds 
489782069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
48981da177e4SLinus Torvalds {
4899773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
49001da177e4SLinus Torvalds }
490182069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
49021da177e4SLinus Torvalds 
490382069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
49041da177e4SLinus Torvalds {
4905773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
49061da177e4SLinus Torvalds }
490782069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
49081da177e4SLinus Torvalds 
490982069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
49101da177e4SLinus Torvalds {
4911773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
49121da177e4SLinus Torvalds }
491382069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
491482069379SAkinobu Mita 			       size_t count)
49151da177e4SLinus Torvalds {
49161da177e4SLinus Torvalds 	int nth;
49171da177e4SLinus Torvalds 
49181da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
4919773642d9SDouglas Gilbert 		sdebug_every_nth = nth;
4920c4837394SDouglas Gilbert 		if (nth && !sdebug_statistics) {
4921c4837394SDouglas Gilbert 			pr_info("every_nth needs statistics=1, set it\n");
4922c4837394SDouglas Gilbert 			sdebug_statistics = true;
4923c4837394SDouglas Gilbert 		}
4924c4837394SDouglas Gilbert 		tweak_cmnd_count();
49251da177e4SLinus Torvalds 		return count;
49261da177e4SLinus Torvalds 	}
49271da177e4SLinus Torvalds 	return -EINVAL;
49281da177e4SLinus Torvalds }
492982069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
49301da177e4SLinus Torvalds 
493182069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
49321da177e4SLinus Torvalds {
4933773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
49341da177e4SLinus Torvalds }
493582069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
493682069379SAkinobu Mita 			      size_t count)
49371da177e4SLinus Torvalds {
49381da177e4SLinus Torvalds 	int n;
493919c8ead7SEwan D. Milne 	bool changed;
49401da177e4SLinus Torvalds 
49411da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
49428d039e22SDouglas Gilbert 		if (n > 256) {
49438d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
49448d039e22SDouglas Gilbert 			return -EINVAL;
49458d039e22SDouglas Gilbert 		}
4946773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
4947773642d9SDouglas Gilbert 		sdebug_max_luns = n;
49481da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
4949773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
495019c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
495119c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
495219c8ead7SEwan D. Milne 
495319c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
495419c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
495519c8ead7SEwan D. Milne 					    host_list) {
495619c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
495719c8ead7SEwan D. Milne 						    dev_list) {
495819c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
495919c8ead7SEwan D. Milne 						dp->uas_bm);
496019c8ead7SEwan D. Milne 				}
496119c8ead7SEwan D. Milne 			}
496219c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
496319c8ead7SEwan D. Milne 		}
49641da177e4SLinus Torvalds 		return count;
49651da177e4SLinus Torvalds 	}
49661da177e4SLinus Torvalds 	return -EINVAL;
49671da177e4SLinus Torvalds }
496882069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
49691da177e4SLinus Torvalds 
497082069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
497178d4e5a0SDouglas Gilbert {
4972773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
497378d4e5a0SDouglas Gilbert }
4974cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
4975cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
497682069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
497782069379SAkinobu Mita 			       size_t count)
497878d4e5a0SDouglas Gilbert {
4979c4837394SDouglas Gilbert 	int j, n, k, a;
4980c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
498178d4e5a0SDouglas Gilbert 
498278d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
4983c4837394SDouglas Gilbert 	    (n <= SDEBUG_CANQUEUE)) {
4984c4837394SDouglas Gilbert 		block_unblock_all_queues(true);
4985c4837394SDouglas Gilbert 		k = 0;
4986c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4987c4837394SDouglas Gilbert 		     ++j, ++sqp) {
4988c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4989c4837394SDouglas Gilbert 			if (a > k)
4990c4837394SDouglas Gilbert 				k = a;
4991c4837394SDouglas Gilbert 		}
4992773642d9SDouglas Gilbert 		sdebug_max_queue = n;
4993c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
4994cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4995cbf67842SDouglas Gilbert 		else if (k >= n)
4996cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4997cbf67842SDouglas Gilbert 		else
4998cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4999c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
500078d4e5a0SDouglas Gilbert 		return count;
500178d4e5a0SDouglas Gilbert 	}
500278d4e5a0SDouglas Gilbert 	return -EINVAL;
500378d4e5a0SDouglas Gilbert }
500482069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
500578d4e5a0SDouglas Gilbert 
500682069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
500778d4e5a0SDouglas Gilbert {
5008773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
500978d4e5a0SDouglas Gilbert }
501082069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
501178d4e5a0SDouglas Gilbert 
501282069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
50131da177e4SLinus Torvalds {
5014773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
50151da177e4SLinus Torvalds }
501682069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
50171da177e4SLinus Torvalds 
501882069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
5019c65b1445SDouglas Gilbert {
5020773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
5021c65b1445SDouglas Gilbert }
502282069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
502382069379SAkinobu Mita 				size_t count)
5024c65b1445SDouglas Gilbert {
5025c65b1445SDouglas Gilbert 	int n;
50260d01c5dfSDouglas Gilbert 	bool changed;
5027c65b1445SDouglas Gilbert 
5028c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5029773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
5030773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
503128898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
50320d01c5dfSDouglas Gilbert 		if (changed) {
50330d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
50340d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
503528898873SFUJITA Tomonori 
50364bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
50370d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
50380d01c5dfSDouglas Gilbert 					    host_list) {
50390d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
50400d01c5dfSDouglas Gilbert 						    dev_list) {
50410d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
50420d01c5dfSDouglas Gilbert 						dp->uas_bm);
50430d01c5dfSDouglas Gilbert 				}
50440d01c5dfSDouglas Gilbert 			}
50454bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
50460d01c5dfSDouglas Gilbert 		}
5047c65b1445SDouglas Gilbert 		return count;
5048c65b1445SDouglas Gilbert 	}
5049c65b1445SDouglas Gilbert 	return -EINVAL;
5050c65b1445SDouglas Gilbert }
505182069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
5052c65b1445SDouglas Gilbert 
505382069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
50541da177e4SLinus Torvalds {
5055773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
50561da177e4SLinus Torvalds }
50571da177e4SLinus Torvalds 
5058fd32119bSDouglas Gilbert static int sdebug_add_adapter(void);
5059fd32119bSDouglas Gilbert static void sdebug_remove_adapter(void);
5060fd32119bSDouglas Gilbert 
506182069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
506282069379SAkinobu Mita 			      size_t count)
50631da177e4SLinus Torvalds {
50641da177e4SLinus Torvalds 	int delta_hosts;
50651da177e4SLinus Torvalds 
5066f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
50671da177e4SLinus Torvalds 		return -EINVAL;
50681da177e4SLinus Torvalds 	if (delta_hosts > 0) {
50691da177e4SLinus Torvalds 		do {
50701da177e4SLinus Torvalds 			sdebug_add_adapter();
50711da177e4SLinus Torvalds 		} while (--delta_hosts);
50721da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
50731da177e4SLinus Torvalds 		do {
50741da177e4SLinus Torvalds 			sdebug_remove_adapter();
50751da177e4SLinus Torvalds 		} while (++delta_hosts);
50761da177e4SLinus Torvalds 	}
50771da177e4SLinus Torvalds 	return count;
50781da177e4SLinus Torvalds }
507982069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
50801da177e4SLinus Torvalds 
508182069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
508223183910SDouglas Gilbert {
5083773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
508423183910SDouglas Gilbert }
508582069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
508682069379SAkinobu Mita 				    size_t count)
508723183910SDouglas Gilbert {
508823183910SDouglas Gilbert 	int n;
508923183910SDouglas Gilbert 
509023183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5091773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
509223183910SDouglas Gilbert 		return count;
509323183910SDouglas Gilbert 	}
509423183910SDouglas Gilbert 	return -EINVAL;
509523183910SDouglas Gilbert }
509682069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
509723183910SDouglas Gilbert 
5098c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
5099c4837394SDouglas Gilbert {
5100c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
5101c4837394SDouglas Gilbert }
5102c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
5103c4837394SDouglas Gilbert 				size_t count)
5104c4837394SDouglas Gilbert {
5105c4837394SDouglas Gilbert 	int n;
5106c4837394SDouglas Gilbert 
5107c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
5108c4837394SDouglas Gilbert 		if (n > 0)
5109c4837394SDouglas Gilbert 			sdebug_statistics = true;
5110c4837394SDouglas Gilbert 		else {
5111c4837394SDouglas Gilbert 			clear_queue_stats();
5112c4837394SDouglas Gilbert 			sdebug_statistics = false;
5113c4837394SDouglas Gilbert 		}
5114c4837394SDouglas Gilbert 		return count;
5115c4837394SDouglas Gilbert 	}
5116c4837394SDouglas Gilbert 	return -EINVAL;
5117c4837394SDouglas Gilbert }
5118c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
5119c4837394SDouglas Gilbert 
512082069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
5121597136abSMartin K. Petersen {
5122773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
5123597136abSMartin K. Petersen }
512482069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
5125597136abSMartin K. Petersen 
5126c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
5127c4837394SDouglas Gilbert {
5128c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
5129c4837394SDouglas Gilbert }
5130c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
5131c4837394SDouglas Gilbert 
513282069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
5133c6a44287SMartin K. Petersen {
5134773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
5135c6a44287SMartin K. Petersen }
513682069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
5137c6a44287SMartin K. Petersen 
513882069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
5139c6a44287SMartin K. Petersen {
5140773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
5141c6a44287SMartin K. Petersen }
514282069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
5143c6a44287SMartin K. Petersen 
514482069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
5145c6a44287SMartin K. Petersen {
5146773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
5147c6a44287SMartin K. Petersen }
514882069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
5149c6a44287SMartin K. Petersen 
515082069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
5151c6a44287SMartin K. Petersen {
5152773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
5153c6a44287SMartin K. Petersen }
515482069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
5155c6a44287SMartin K. Petersen 
515682069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
515744d92694SMartin K. Petersen {
515844d92694SMartin K. Petersen 	ssize_t count;
515944d92694SMartin K. Petersen 
51605b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
516144d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
516244d92694SMartin K. Petersen 				 sdebug_store_sectors);
516344d92694SMartin K. Petersen 
5164c7badc90STejun Heo 	count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
5165c7badc90STejun Heo 			  (int)map_size, map_storep);
516644d92694SMartin K. Petersen 	buf[count++] = '\n';
5167c7badc90STejun Heo 	buf[count] = '\0';
516844d92694SMartin K. Petersen 
516944d92694SMartin K. Petersen 	return count;
517044d92694SMartin K. Petersen }
517182069379SAkinobu Mita static DRIVER_ATTR_RO(map);
517244d92694SMartin K. Petersen 
517382069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
5174d986788bSMartin Pitt {
5175773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
5176d986788bSMartin Pitt }
517782069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
517882069379SAkinobu Mita 			       size_t count)
5179d986788bSMartin Pitt {
5180d986788bSMartin Pitt 	int n;
5181d986788bSMartin Pitt 
5182d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5183773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
5184d986788bSMartin Pitt 		return count;
5185d986788bSMartin Pitt 	}
5186d986788bSMartin Pitt 	return -EINVAL;
5187d986788bSMartin Pitt }
518882069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
5189d986788bSMartin Pitt 
5190cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
5191cbf67842SDouglas Gilbert {
5192773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
5193cbf67842SDouglas Gilbert }
5194185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
5195cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
5196cbf67842SDouglas Gilbert 			       size_t count)
5197cbf67842SDouglas Gilbert {
5198185dd232SDouglas Gilbert 	int n;
5199cbf67842SDouglas Gilbert 
5200cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5201185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
5202185dd232SDouglas Gilbert 		return count;
5203cbf67842SDouglas Gilbert 	}
5204cbf67842SDouglas Gilbert 	return -EINVAL;
5205cbf67842SDouglas Gilbert }
5206cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
5207cbf67842SDouglas Gilbert 
5208c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
5209c2248fc9SDouglas Gilbert {
5210773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
5211c2248fc9SDouglas Gilbert }
5212c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
5213c2248fc9SDouglas Gilbert 			    size_t count)
5214c2248fc9SDouglas Gilbert {
5215c2248fc9SDouglas Gilbert 	int n;
5216c2248fc9SDouglas Gilbert 
5217c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
5218773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
5219c2248fc9SDouglas Gilbert 		return count;
5220c2248fc9SDouglas Gilbert 	}
5221c2248fc9SDouglas Gilbert 	return -EINVAL;
5222c2248fc9SDouglas Gilbert }
5223c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
5224c2248fc9SDouglas Gilbert 
522509ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
522609ba24c1SDouglas Gilbert {
522709ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
522809ba24c1SDouglas Gilbert }
522909ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
523009ba24c1SDouglas Gilbert 
52319b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
52329b760fd8SDouglas Gilbert {
52339b760fd8SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
52349b760fd8SDouglas Gilbert }
52359b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
52369b760fd8SDouglas Gilbert 			     size_t count)
52379b760fd8SDouglas Gilbert {
52389b760fd8SDouglas Gilbert 	int ret, n;
52399b760fd8SDouglas Gilbert 
52409b760fd8SDouglas Gilbert 	ret = kstrtoint(buf, 0, &n);
52419b760fd8SDouglas Gilbert 	if (ret)
52429b760fd8SDouglas Gilbert 		return ret;
52439b760fd8SDouglas Gilbert 	sdebug_cdb_len = n;
52449b760fd8SDouglas Gilbert 	all_config_cdb_len();
52459b760fd8SDouglas Gilbert 	return count;
52469b760fd8SDouglas Gilbert }
52479b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len);
52489b760fd8SDouglas Gilbert 
5249cbf67842SDouglas Gilbert 
525082069379SAkinobu Mita /* Note: The following array creates attribute files in the
525123183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
525223183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
525323183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
525423183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
525523183910SDouglas Gilbert  */
52566ecaff7fSRandy Dunlap 
525782069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
525882069379SAkinobu Mita 	&driver_attr_delay.attr,
525982069379SAkinobu Mita 	&driver_attr_opts.attr,
526082069379SAkinobu Mita 	&driver_attr_ptype.attr,
526182069379SAkinobu Mita 	&driver_attr_dsense.attr,
526282069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
526382069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
526482069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
526582069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
526682069379SAkinobu Mita 	&driver_attr_num_parts.attr,
526782069379SAkinobu Mita 	&driver_attr_every_nth.attr,
526882069379SAkinobu Mita 	&driver_attr_max_luns.attr,
526982069379SAkinobu Mita 	&driver_attr_max_queue.attr,
527082069379SAkinobu Mita 	&driver_attr_no_uld.attr,
527182069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
527282069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
527382069379SAkinobu Mita 	&driver_attr_add_host.attr,
527482069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
527582069379SAkinobu Mita 	&driver_attr_sector_size.attr,
5276c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
5277c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
527882069379SAkinobu Mita 	&driver_attr_dix.attr,
527982069379SAkinobu Mita 	&driver_attr_dif.attr,
528082069379SAkinobu Mita 	&driver_attr_guard.attr,
528182069379SAkinobu Mita 	&driver_attr_ato.attr,
528282069379SAkinobu Mita 	&driver_attr_map.attr,
528382069379SAkinobu Mita 	&driver_attr_removable.attr,
5284cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
5285cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
5286c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
528709ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
52889b760fd8SDouglas Gilbert 	&driver_attr_cdb_len.attr,
528982069379SAkinobu Mita 	NULL,
529082069379SAkinobu Mita };
529182069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
52921da177e4SLinus Torvalds 
529311ddcecaSAkinobu Mita static struct device *pseudo_primary;
52948dea0d02SFUJITA Tomonori 
52951da177e4SLinus Torvalds static int __init scsi_debug_init(void)
52961da177e4SLinus Torvalds {
52975f2578e5SFUJITA Tomonori 	unsigned long sz;
52981da177e4SLinus Torvalds 	int host_to_add;
52991da177e4SLinus Torvalds 	int k;
53006ecaff7fSRandy Dunlap 	int ret;
53011da177e4SLinus Torvalds 
5302cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
5303cbf67842SDouglas Gilbert 
5304773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
5305c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
5306773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
5307773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
5308c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
5309cbf67842SDouglas Gilbert 
5310773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
5311597136abSMartin K. Petersen 	case  512:
5312597136abSMartin K. Petersen 	case 1024:
5313597136abSMartin K. Petersen 	case 2048:
5314597136abSMartin K. Petersen 	case 4096:
5315597136abSMartin K. Petersen 		break;
5316597136abSMartin K. Petersen 	default:
5317773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
5318597136abSMartin K. Petersen 		return -EINVAL;
5319597136abSMartin K. Petersen 	}
5320597136abSMartin K. Petersen 
5321773642d9SDouglas Gilbert 	switch (sdebug_dif) {
53228475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
5323f46eb0e9SDouglas Gilbert 		break;
53248475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
53258475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
53268475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
5327f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
5328c6a44287SMartin K. Petersen 		break;
5329c6a44287SMartin K. Petersen 
5330c6a44287SMartin K. Petersen 	default:
5331c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
5332c6a44287SMartin K. Petersen 		return -EINVAL;
5333c6a44287SMartin K. Petersen 	}
5334c6a44287SMartin K. Petersen 
5335773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
5336c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
5337c6a44287SMartin K. Petersen 		return -EINVAL;
5338c6a44287SMartin K. Petersen 	}
5339c6a44287SMartin K. Petersen 
5340773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
5341c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
5342c6a44287SMartin K. Petersen 		return -EINVAL;
5343c6a44287SMartin K. Petersen 	}
5344c6a44287SMartin K. Petersen 
5345773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
5346773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
5347ea61fca5SMartin K. Petersen 		return -EINVAL;
5348ea61fca5SMartin K. Petersen 	}
53498d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
53508d039e22SDouglas Gilbert 		pr_warn("max_luns can be no more than 256, use default\n");
53518d039e22SDouglas Gilbert 		sdebug_max_luns = DEF_MAX_LUNS;
53528d039e22SDouglas Gilbert 	}
5353ea61fca5SMartin K. Petersen 
5354773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
5355773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
5356ea61fca5SMartin K. Petersen 		return -EINVAL;
5357ea61fca5SMartin K. Petersen 	}
5358ea61fca5SMartin K. Petersen 
5359c4837394SDouglas Gilbert 	if (submit_queues < 1) {
5360c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
5361c4837394SDouglas Gilbert 		return -EINVAL;
5362c4837394SDouglas Gilbert 	}
5363c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
5364c4837394SDouglas Gilbert 			       GFP_KERNEL);
5365c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
5366c4837394SDouglas Gilbert 		return -ENOMEM;
5367c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
5368c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
5369c4837394SDouglas Gilbert 
5370773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
5371773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
5372773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
5373773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
537428898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
53751da177e4SLinus Torvalds 
53761da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
53771da177e4SLinus Torvalds 	sdebug_heads = 8;
53781da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
5379773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
53801da177e4SLinus Torvalds 		sdebug_heads = 64;
5381773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
5382fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
53831da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
53841da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
53851da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
53861da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
53871da177e4SLinus Torvalds 		sdebug_heads = 255;
53881da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
53891da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
53901da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
53911da177e4SLinus Torvalds 	}
53921da177e4SLinus Torvalds 
5393b01f6f83SDouglas Gilbert 	if (sdebug_fake_rw == 0) {
53941da177e4SLinus Torvalds 		fake_storep = vmalloc(sz);
53951da177e4SLinus Torvalds 		if (NULL == fake_storep) {
5396c1287970STomas Winkler 			pr_err("out of memory, 1\n");
5397c4837394SDouglas Gilbert 			ret = -ENOMEM;
5398c4837394SDouglas Gilbert 			goto free_q_arr;
53991da177e4SLinus Torvalds 		}
54001da177e4SLinus Torvalds 		memset(fake_storep, 0, sz);
5401773642d9SDouglas Gilbert 		if (sdebug_num_parts > 0)
5402f58b0efbSFUJITA Tomonori 			sdebug_build_parts(fake_storep, sz);
5403cbf67842SDouglas Gilbert 	}
54041da177e4SLinus Torvalds 
5405773642d9SDouglas Gilbert 	if (sdebug_dix) {
5406c6a44287SMartin K. Petersen 		int dif_size;
5407c6a44287SMartin K. Petersen 
54086ebf105cSChristoph Hellwig 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
5409c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
5410c6a44287SMartin K. Petersen 
5411c1287970STomas Winkler 		pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
5412c6a44287SMartin K. Petersen 
5413c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
5414c1287970STomas Winkler 			pr_err("out of mem. (DIX)\n");
5415c6a44287SMartin K. Petersen 			ret = -ENOMEM;
5416c6a44287SMartin K. Petersen 			goto free_vm;
5417c6a44287SMartin K. Petersen 		}
5418c6a44287SMartin K. Petersen 
5419c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
5420c6a44287SMartin K. Petersen 	}
5421c6a44287SMartin K. Petersen 
54225b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
54235b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
5424773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
5425773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
54266014759cSMartin K. Petersen 
5427773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
5428773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
54296014759cSMartin K. Petersen 
5430773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
5431773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
54326014759cSMartin K. Petersen 
5433773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
5434773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
5435773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
5436c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
5437c4837394SDouglas Gilbert 			ret = -EINVAL;
5438c4837394SDouglas Gilbert 			goto free_vm;
543944d92694SMartin K. Petersen 		}
544044d92694SMartin K. Petersen 
5441b90ebc3dSAkinobu Mita 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
544242bc47b3SKees Cook 		map_storep = vmalloc(array_size(sizeof(long),
544342bc47b3SKees Cook 						BITS_TO_LONGS(map_size)));
544444d92694SMartin K. Petersen 
5445c1287970STomas Winkler 		pr_info("%lu provisioning blocks\n", map_size);
544644d92694SMartin K. Petersen 
544744d92694SMartin K. Petersen 		if (map_storep == NULL) {
5448c1287970STomas Winkler 			pr_err("out of mem. (MAP)\n");
544944d92694SMartin K. Petersen 			ret = -ENOMEM;
545044d92694SMartin K. Petersen 			goto free_vm;
545144d92694SMartin K. Petersen 		}
545244d92694SMartin K. Petersen 
5453b90ebc3dSAkinobu Mita 		bitmap_zero(map_storep, map_size);
545444d92694SMartin K. Petersen 
545544d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
5456773642d9SDouglas Gilbert 		if (sdebug_num_parts)
545744d92694SMartin K. Petersen 			map_region(0, 2);
545844d92694SMartin K. Petersen 	}
545944d92694SMartin K. Petersen 
54609b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
54619b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
5462c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
54639b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
54646ecaff7fSRandy Dunlap 		goto free_vm;
54656ecaff7fSRandy Dunlap 	}
54666ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
54676ecaff7fSRandy Dunlap 	if (ret < 0) {
5468c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
54696ecaff7fSRandy Dunlap 		goto dev_unreg;
54706ecaff7fSRandy Dunlap 	}
54716ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
54726ecaff7fSRandy Dunlap 	if (ret < 0) {
5473c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
54746ecaff7fSRandy Dunlap 		goto bus_unreg;
54756ecaff7fSRandy Dunlap 	}
54761da177e4SLinus Torvalds 
5477773642d9SDouglas Gilbert 	host_to_add = sdebug_add_host;
5478773642d9SDouglas Gilbert 	sdebug_add_host = 0;
54791da177e4SLinus Torvalds 
54801da177e4SLinus Torvalds 	for (k = 0; k < host_to_add; k++) {
54811da177e4SLinus Torvalds 		if (sdebug_add_adapter()) {
5482c1287970STomas Winkler 			pr_err("sdebug_add_adapter failed k=%d\n", k);
54831da177e4SLinus Torvalds 			break;
54841da177e4SLinus Torvalds 		}
54851da177e4SLinus Torvalds 	}
54861da177e4SLinus Torvalds 
5487773642d9SDouglas Gilbert 	if (sdebug_verbose)
5488773642d9SDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_add_host);
5489c1287970STomas Winkler 
54901da177e4SLinus Torvalds 	return 0;
54916ecaff7fSRandy Dunlap 
54926ecaff7fSRandy Dunlap bus_unreg:
54936ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
54946ecaff7fSRandy Dunlap dev_unreg:
54959b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
54966ecaff7fSRandy Dunlap free_vm:
549744d92694SMartin K. Petersen 	vfree(map_storep);
5498c6a44287SMartin K. Petersen 	vfree(dif_storep);
54996ecaff7fSRandy Dunlap 	vfree(fake_storep);
5500c4837394SDouglas Gilbert free_q_arr:
5501c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
55026ecaff7fSRandy Dunlap 	return ret;
55031da177e4SLinus Torvalds }
55041da177e4SLinus Torvalds 
55051da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
55061da177e4SLinus Torvalds {
5507773642d9SDouglas Gilbert 	int k = sdebug_add_host;
55081da177e4SLinus Torvalds 
55091da177e4SLinus Torvalds 	stop_all_queued();
55101da177e4SLinus Torvalds 	for (; k; k--)
55111da177e4SLinus Torvalds 		sdebug_remove_adapter();
551252ab9768SLuis Henriques 	free_all_queued();
55131da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
55141da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
55159b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
55161da177e4SLinus Torvalds 
55174d2b496fSEwan D. Milne 	vfree(map_storep);
5518c6a44287SMartin K. Petersen 	vfree(dif_storep);
55191da177e4SLinus Torvalds 	vfree(fake_storep);
5520c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
55211da177e4SLinus Torvalds }
55221da177e4SLinus Torvalds 
55231da177e4SLinus Torvalds device_initcall(scsi_debug_init);
55241da177e4SLinus Torvalds module_exit(scsi_debug_exit);
55251da177e4SLinus Torvalds 
55261da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev)
55271da177e4SLinus Torvalds {
55281da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
55291da177e4SLinus Torvalds 
55301da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
55311da177e4SLinus Torvalds 	kfree(sdbg_host);
55321da177e4SLinus Torvalds }
55331da177e4SLinus Torvalds 
55341da177e4SLinus Torvalds static int sdebug_add_adapter(void)
55351da177e4SLinus Torvalds {
55361da177e4SLinus Torvalds 	int k, devs_per_host;
55371da177e4SLinus Torvalds 	int error = 0;
55381da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
55398b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
55401da177e4SLinus Torvalds 
554124669f75SJes Sorensen 	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
55429a051019SDouglas Gilbert 	if (sdbg_host == NULL) {
5543c1287970STomas Winkler 		pr_err("out of memory at line %d\n", __LINE__);
55441da177e4SLinus Torvalds 		return -ENOMEM;
55451da177e4SLinus Torvalds 	}
55461da177e4SLinus Torvalds 
55471da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
55481da177e4SLinus Torvalds 
5549773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
55501da177e4SLinus Torvalds 	for (k = 0; k < devs_per_host; k++) {
55515cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
55525cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
5553c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
55541da177e4SLinus Torvalds 			error = -ENOMEM;
55551da177e4SLinus Torvalds 			goto clean;
55561da177e4SLinus Torvalds 		}
55571da177e4SLinus Torvalds 	}
55581da177e4SLinus Torvalds 
55591da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
55601da177e4SLinus Torvalds 	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
55611da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
55621da177e4SLinus Torvalds 
55631da177e4SLinus Torvalds 	sdbg_host->dev.bus = &pseudo_lld_bus;
55649b906779SNicholas Bellinger 	sdbg_host->dev.parent = pseudo_primary;
55651da177e4SLinus Torvalds 	sdbg_host->dev.release = &sdebug_release_adapter;
5566773642d9SDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
55671da177e4SLinus Torvalds 
55681da177e4SLinus Torvalds 	error = device_register(&sdbg_host->dev);
55691da177e4SLinus Torvalds 
55701da177e4SLinus Torvalds 	if (error)
55711da177e4SLinus Torvalds 		goto clean;
55721da177e4SLinus Torvalds 
5573773642d9SDouglas Gilbert 	++sdebug_add_host;
55741da177e4SLinus Torvalds 	return error;
55751da177e4SLinus Torvalds 
55761da177e4SLinus Torvalds clean:
55778b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
55788b40228fSFUJITA Tomonori 				 dev_list) {
55791da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
55801da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
55811da177e4SLinus Torvalds 	}
55821da177e4SLinus Torvalds 
55831da177e4SLinus Torvalds 	kfree(sdbg_host);
55841da177e4SLinus Torvalds 	return error;
55851da177e4SLinus Torvalds }
55861da177e4SLinus Torvalds 
55871da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
55881da177e4SLinus Torvalds {
55891da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host = NULL;
55901da177e4SLinus Torvalds 
55911da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
55921da177e4SLinus Torvalds 	if (!list_empty(&sdebug_host_list)) {
55931da177e4SLinus Torvalds 		sdbg_host = list_entry(sdebug_host_list.prev,
55941da177e4SLinus Torvalds 				       struct sdebug_host_info, host_list);
55951da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
55961da177e4SLinus Torvalds 	}
55971da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
55981da177e4SLinus Torvalds 
55991da177e4SLinus Torvalds 	if (!sdbg_host)
56001da177e4SLinus Torvalds 		return;
56011da177e4SLinus Torvalds 
56021da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
5603773642d9SDouglas Gilbert 	--sdebug_add_host;
56041da177e4SLinus Torvalds }
56051da177e4SLinus Torvalds 
5606fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
5607cbf67842SDouglas Gilbert {
5608cbf67842SDouglas Gilbert 	int num_in_q = 0;
5609cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5610cbf67842SDouglas Gilbert 
5611c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
5612cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
5613cbf67842SDouglas Gilbert 	if (NULL == devip) {
5614c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
5615cbf67842SDouglas Gilbert 		return	-ENODEV;
5616cbf67842SDouglas Gilbert 	}
5617cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5618c40ecc12SChristoph Hellwig 
5619cbf67842SDouglas Gilbert 	if (qdepth < 1)
5620cbf67842SDouglas Gilbert 		qdepth = 1;
5621c4837394SDouglas Gilbert 	/* allow to exceed max host qc_arr elements for testing */
5622c4837394SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE + 10)
5623c4837394SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE + 10;
5624db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
5625cbf67842SDouglas Gilbert 
5626773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
5627c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
5628c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
5629cbf67842SDouglas Gilbert 	}
5630c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
5631cbf67842SDouglas Gilbert 	return sdev->queue_depth;
5632cbf67842SDouglas Gilbert }
5633cbf67842SDouglas Gilbert 
5634c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
5635817fd66bSDouglas Gilbert {
5636c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
5637773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
5638773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
5639773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
5640c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
5641773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
5642817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
5643c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
5644817fd66bSDouglas Gilbert 	}
5645c4837394SDouglas Gilbert 	return false;
5646817fd66bSDouglas Gilbert }
5647817fd66bSDouglas Gilbert 
56487ee6d1b4SBart Van Assche static bool fake_host_busy(struct scsi_cmnd *scp)
56497ee6d1b4SBart Van Assche {
56507ee6d1b4SBart Van Assche 	return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
56517ee6d1b4SBart Van Assche 		(atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
56527ee6d1b4SBart Van Assche }
56537ee6d1b4SBart Van Assche 
5654fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5655fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
5656c2248fc9SDouglas Gilbert {
5657c2248fc9SDouglas Gilbert 	u8 sdeb_i;
5658c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
5659c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
5660c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
5661c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
5662c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
5663c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5664f66b8517SMartin Wilck 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
5665c2248fc9SDouglas Gilbert 	int k, na;
5666c2248fc9SDouglas Gilbert 	int errsts = 0;
5667c2248fc9SDouglas Gilbert 	u32 flags;
5668c2248fc9SDouglas Gilbert 	u16 sa;
5669c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
5670c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
5671c2248fc9SDouglas Gilbert 
5672c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
5673c4837394SDouglas Gilbert 	if (sdebug_statistics)
5674c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
5675f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
5676f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
5677c2248fc9SDouglas Gilbert 		char b[120];
5678c2248fc9SDouglas Gilbert 		int n, len, sb;
5679c2248fc9SDouglas Gilbert 
5680c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
5681c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
5682c2248fc9SDouglas Gilbert 		if (len > 32)
5683c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
5684c2248fc9SDouglas Gilbert 		else {
5685c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
5686c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
5687c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
5688c2248fc9SDouglas Gilbert 		}
5689458df78bSBart Van Assche 		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
5690458df78bSBart Van Assche 			    blk_mq_unique_tag(scp->request), b);
5691c2248fc9SDouglas Gilbert 	}
56927ee6d1b4SBart Van Assche 	if (fake_host_busy(scp))
56937ee6d1b4SBart Van Assche 		return SCSI_MLQUEUE_HOST_BUSY;
569434d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
5695f46eb0e9SDouglas Gilbert 	if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5696f46eb0e9SDouglas Gilbert 		goto err_out;
5697c2248fc9SDouglas Gilbert 
5698c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
5699c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
5700c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
5701f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
5702f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5703c2248fc9SDouglas Gilbert 		if (NULL == devip)
5704f46eb0e9SDouglas Gilbert 			goto err_out;
5705c2248fc9SDouglas Gilbert 	}
5706c2248fc9SDouglas Gilbert 	na = oip->num_attached;
5707c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
5708c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
5709c2248fc9SDouglas Gilbert 		r_oip = oip;
5710c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
5711c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
5712c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
5713c2248fc9SDouglas Gilbert 			else
5714c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
5715c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5716c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
5717c2248fc9SDouglas Gilbert 					break;
5718c2248fc9SDouglas Gilbert 			}
5719c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
5720c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5721c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
5722c2248fc9SDouglas Gilbert 					break;
5723c2248fc9SDouglas Gilbert 			}
5724c2248fc9SDouglas Gilbert 		}
5725c2248fc9SDouglas Gilbert 		if (k > na) {
5726c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
5727c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5728c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
5729c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5730c2248fc9SDouglas Gilbert 			else
5731c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
5732c2248fc9SDouglas Gilbert 			goto check_cond;
5733c2248fc9SDouglas Gilbert 		}
5734c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
5735c2248fc9SDouglas Gilbert 	flags = oip->flags;
5736f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
5737c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5738c2248fc9SDouglas Gilbert 		goto check_cond;
5739c2248fc9SDouglas Gilbert 	}
5740f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
5741773642d9SDouglas Gilbert 		if (sdebug_verbose)
5742773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5743773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
5744c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5745c2248fc9SDouglas Gilbert 		goto check_cond;
5746c2248fc9SDouglas Gilbert 	}
5747f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
5748c2248fc9SDouglas Gilbert 		u8 rem;
5749c2248fc9SDouglas Gilbert 		int j;
5750c2248fc9SDouglas Gilbert 
5751c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5752c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
5753c2248fc9SDouglas Gilbert 			if (rem) {
5754c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
5755c2248fc9SDouglas Gilbert 					if (0x80 & rem)
5756c2248fc9SDouglas Gilbert 						break;
5757c2248fc9SDouglas Gilbert 				}
5758c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5759c2248fc9SDouglas Gilbert 				goto check_cond;
5760c2248fc9SDouglas Gilbert 			}
5761c2248fc9SDouglas Gilbert 		}
5762c2248fc9SDouglas Gilbert 	}
5763f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
5764b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
5765b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
5766f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
5767c2248fc9SDouglas Gilbert 		if (errsts)
5768c2248fc9SDouglas Gilbert 			goto check_cond;
5769c2248fc9SDouglas Gilbert 	}
5770c4837394SDouglas Gilbert 	if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
5771c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
5772773642d9SDouglas Gilbert 		if (sdebug_verbose)
5773c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5774c2248fc9SDouglas Gilbert 				    "%s\n", my_name, "initializing command "
5775c2248fc9SDouglas Gilbert 				    "required");
5776c2248fc9SDouglas Gilbert 		errsts = check_condition_result;
5777c2248fc9SDouglas Gilbert 		goto fini;
5778c2248fc9SDouglas Gilbert 	}
5779773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
5780c2248fc9SDouglas Gilbert 		goto fini;
5781f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
5782c4837394SDouglas Gilbert 		if (fake_timeout(scp))
5783c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
5784c2248fc9SDouglas Gilbert 	}
5785f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
5786f66b8517SMartin Wilck 		pfp = oip->pfp;	/* calls a resp_* function */
5787f66b8517SMartin Wilck 	else
5788f66b8517SMartin Wilck 		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
5789c2248fc9SDouglas Gilbert 
5790c2248fc9SDouglas Gilbert fini:
579110bde980SDouglas Gilbert 	if (F_DELAY_OVERR & flags)
5792f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
579380c49563SDouglas Gilbert 	else if ((sdebug_jdelay || sdebug_ndelay) && (flags & F_LONG_DELAY)) {
579480c49563SDouglas Gilbert 		/*
57954f2c8bf6SDouglas Gilbert 		 * If any delay is active, for F_SSU_DELAY want at least 1
579680c49563SDouglas Gilbert 		 * second and if sdebug_jdelay>0 want a long delay of that
57974f2c8bf6SDouglas Gilbert 		 * many seconds; for F_SYNC_DELAY want 1/20 of that.
579880c49563SDouglas Gilbert 		 */
579980c49563SDouglas Gilbert 		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
58004f2c8bf6SDouglas Gilbert 		int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
580180c49563SDouglas Gilbert 
58024f2c8bf6SDouglas Gilbert 		jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
5803f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
580480c49563SDouglas Gilbert 	} else
5805f66b8517SMartin Wilck 		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
580610bde980SDouglas Gilbert 				     sdebug_ndelay);
5807c2248fc9SDouglas Gilbert check_cond:
5808f66b8517SMartin Wilck 	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
5809f46eb0e9SDouglas Gilbert err_out:
5810f66b8517SMartin Wilck 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
5811c2248fc9SDouglas Gilbert }
5812c2248fc9SDouglas Gilbert 
58139e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
5814c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
5815c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
58169e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
58179e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
58189e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
58199e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
58209e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
58219e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
58229e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
5823185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
5824cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
58259e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
58269e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
5827cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
5828cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
58299e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
5830c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
58319e603ca0SFUJITA Tomonori 	.this_id =		7,
583265e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
5833cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
58346bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
58359e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
58369e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
5837c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
58389e603ca0SFUJITA Tomonori };
58399e603ca0SFUJITA Tomonori 
58401da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev)
58411da177e4SLinus Torvalds {
58421da177e4SLinus Torvalds 	int error = 0;
58431da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
58441da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
5845f46eb0e9SDouglas Gilbert 	int hprot;
58461da177e4SLinus Torvalds 
58471da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
58481da177e4SLinus Torvalds 
5849773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
5850773642d9SDouglas Gilbert 	if (sdebug_clustering)
58510759c666SAkinobu Mita 		sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
58521da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
58531da177e4SLinus Torvalds 	if (NULL == hpnt) {
5854c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
58551da177e4SLinus Torvalds 		error = -ENODEV;
58561da177e4SLinus Torvalds 		return error;
58571da177e4SLinus Torvalds 	}
5858c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
58599b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
5860c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
5861c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
5862c4837394SDouglas Gilbert 	}
5863c4837394SDouglas Gilbert 	/* Decide whether to tell scsi subsystem that we want mq */
5864c4837394SDouglas Gilbert 	/* Following should give the same answer for each host */
5865458df78bSBart Van Assche 	if (shost_use_blk_mq(hpnt))
5866c4837394SDouglas Gilbert 		hpnt->nr_hw_queues = submit_queues;
58671da177e4SLinus Torvalds 
58681da177e4SLinus Torvalds 	sdbg_host->shost = hpnt;
58691da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
5870773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5871773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
58721da177e4SLinus Torvalds 	else
5873773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
5874773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
5875f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
58761da177e4SLinus Torvalds 
5877f46eb0e9SDouglas Gilbert 	hprot = 0;
5878c6a44287SMartin K. Petersen 
5879773642d9SDouglas Gilbert 	switch (sdebug_dif) {
5880c6a44287SMartin K. Petersen 
58818475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
5882f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
5883773642d9SDouglas Gilbert 		if (sdebug_dix)
5884f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
5885c6a44287SMartin K. Petersen 		break;
5886c6a44287SMartin K. Petersen 
58878475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
5888f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
5889773642d9SDouglas Gilbert 		if (sdebug_dix)
5890f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
5891c6a44287SMartin K. Petersen 		break;
5892c6a44287SMartin K. Petersen 
58938475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
5894f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
5895773642d9SDouglas Gilbert 		if (sdebug_dix)
5896f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
5897c6a44287SMartin K. Petersen 		break;
5898c6a44287SMartin K. Petersen 
5899c6a44287SMartin K. Petersen 	default:
5900773642d9SDouglas Gilbert 		if (sdebug_dix)
5901f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
5902c6a44287SMartin K. Petersen 		break;
5903c6a44287SMartin K. Petersen 	}
5904c6a44287SMartin K. Petersen 
5905f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
5906c6a44287SMartin K. Petersen 
5907f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
5908c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
5909f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5910f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5911f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5912f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5913f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5914f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5915f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
5916c6a44287SMartin K. Petersen 
5917773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
5918c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5919c6a44287SMartin K. Petersen 	else
5920c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5921c6a44287SMartin K. Petersen 
5922773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5923773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
5924c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
5925c4837394SDouglas Gilbert 		sdebug_statistics = true;
59261da177e4SLinus Torvalds 	error = scsi_add_host(hpnt, &sdbg_host->dev);
59271da177e4SLinus Torvalds 	if (error) {
5928c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
59291da177e4SLinus Torvalds 		error = -ENODEV;
59301da177e4SLinus Torvalds 		scsi_host_put(hpnt);
59311da177e4SLinus Torvalds 	} else
59321da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
59331da177e4SLinus Torvalds 
59341da177e4SLinus Torvalds 	return error;
59351da177e4SLinus Torvalds }
59361da177e4SLinus Torvalds 
59371da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *dev)
59381da177e4SLinus Torvalds {
59391da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
59408b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
59411da177e4SLinus Torvalds 
59421da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
59431da177e4SLinus Torvalds 
59441da177e4SLinus Torvalds 	if (!sdbg_host) {
5945c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
59461da177e4SLinus Torvalds 		return -ENODEV;
59471da177e4SLinus Torvalds 	}
59481da177e4SLinus Torvalds 
59491da177e4SLinus Torvalds 	scsi_remove_host(sdbg_host->shost);
59501da177e4SLinus Torvalds 
59518b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
59528b40228fSFUJITA Tomonori 				 dev_list) {
59531da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
59541da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
59551da177e4SLinus Torvalds 	}
59561da177e4SLinus Torvalds 
59571da177e4SLinus Torvalds 	scsi_host_put(sdbg_host->shost);
59581da177e4SLinus Torvalds 	return 0;
59591da177e4SLinus Torvalds }
59601da177e4SLinus Torvalds 
59618dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
59628dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
59631da177e4SLinus Torvalds {
59648dea0d02SFUJITA Tomonori 	return 1;
59658dea0d02SFUJITA Tomonori }
59661da177e4SLinus Torvalds 
59678dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
59688dea0d02SFUJITA Tomonori 	.name = "pseudo",
59698dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
59708dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
59718dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
597282069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
59738dea0d02SFUJITA Tomonori };
5974