xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision e5203cf0)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
31da177e4SLinus Torvalds  *  Copyright (C) 1992  Eric Youngdale
41da177e4SLinus Torvalds  *  Simulate a host adapter with 2 disks attached.  Do a lot of checking
51da177e4SLinus Torvalds  *  to make sure that we are not getting blocks mixed up, and PANIC if
61da177e4SLinus Torvalds  *  anything out of the ordinary is seen.
71da177e4SLinus Torvalds  * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
81da177e4SLinus Torvalds  *
9773642d9SDouglas Gilbert  * Copyright (C) 2001 - 2016 Douglas Gilbert
101da177e4SLinus Torvalds  *
11773642d9SDouglas Gilbert  * This program is free software; you can redistribute it and/or modify
12773642d9SDouglas Gilbert  * it under the terms of the GNU General Public License as published by
13773642d9SDouglas Gilbert  * the Free Software Foundation; either version 2, or (at your option)
14773642d9SDouglas Gilbert  * any later version.
151da177e4SLinus Torvalds  *
1678d4e5a0SDouglas Gilbert  *  For documentation see http://sg.danny.cz/sg/sdebug26.html
171da177e4SLinus Torvalds  *
181da177e4SLinus Torvalds  */
191da177e4SLinus Torvalds 
20c1287970STomas Winkler 
21c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
22c1287970STomas Winkler 
231da177e4SLinus Torvalds #include <linux/module.h>
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds #include <linux/kernel.h>
261da177e4SLinus Torvalds #include <linux/errno.h>
27b333a819SDouglas Gilbert #include <linux/jiffies.h>
285a0e3ad6STejun Heo #include <linux/slab.h>
291da177e4SLinus Torvalds #include <linux/types.h>
301da177e4SLinus Torvalds #include <linux/string.h>
311da177e4SLinus Torvalds #include <linux/genhd.h>
321da177e4SLinus Torvalds #include <linux/fs.h>
331da177e4SLinus Torvalds #include <linux/init.h>
341da177e4SLinus Torvalds #include <linux/proc_fs.h>
351da177e4SLinus Torvalds #include <linux/vmalloc.h>
361da177e4SLinus Torvalds #include <linux/moduleparam.h>
37852e034dSJens Axboe #include <linux/scatterlist.h>
381da177e4SLinus Torvalds #include <linux/blkdev.h>
39c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h>
40cbf67842SDouglas Gilbert #include <linux/spinlock.h>
41cbf67842SDouglas Gilbert #include <linux/interrupt.h>
42cbf67842SDouglas Gilbert #include <linux/atomic.h>
43cbf67842SDouglas Gilbert #include <linux/hrtimer.h>
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 */
64b01f6f83SDouglas Gilbert #define SDEBUG_VERSION "1.86"
65b01f6f83SDouglas Gilbert static const char *sdebug_version_date = "20160430";
66cbf67842SDouglas Gilbert 
67cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
681da177e4SLinus Torvalds 
696f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
70c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
71c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
72c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
731da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
74c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
751da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7622017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
771da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
78c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
79cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
80cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
8119c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
8219c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8322017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8422017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
85cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
86cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
87cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
8822017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9
891da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
906f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
91c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
92c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
9322017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d
94acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1	/* with TARGET_CHANGED_ASC */
95acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
961da177e4SLinus Torvalds 
976f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
986f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
996f3cbf55SDouglas Gilbert 
1001da177e4SLinus Torvalds /* Default values for driver parameters */
1011da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1021da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1031da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1041da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1051da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1061da177e4SLinus Torvalds  */
1075b94e232SMartin K. Petersen #define DEF_ATO 1
108c2206098SDouglas Gilbert #define DEF_JDELAY   1		/* if > 0 unit is a jiffy */
1091da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1105b94e232SMartin K. Petersen #define DEF_DIF 0
1115b94e232SMartin K. Petersen #define DEF_DIX 0
1125b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1131da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1145b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1155b94e232SMartin K. Petersen #define DEF_GUARD 0
116cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1175b94e232SMartin K. Petersen #define DEF_LBPU 0
1185b94e232SMartin K. Petersen #define DEF_LBPWS 0
1195b94e232SMartin K. Petersen #define DEF_LBPWS10 0
120be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1215b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
122cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1235b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1241da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1251da177e4SLinus Torvalds #define DEF_OPTS   0
12632c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1275b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
12886e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0
129b01f6f83SDouglas Gilbert #define DEF_PTYPE   TYPE_DISK
130d986788bSMartin Pitt #define DEF_REMOVABLE false
131760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
1325b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1335b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1345b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1356014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1366014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1375b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1385b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1395b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
140c2248fc9SDouglas Gilbert #define DEF_STRICT 0
141c4837394SDouglas Gilbert #define DEF_STATISTICS false
142c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1
14309ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0
144c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999
1451da177e4SLinus Torvalds 
146b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0
147b01f6f83SDouglas Gilbert 
148773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
149773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
150773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
151773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
152773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
153773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
154773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
155773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
156773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
157773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
158773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
159773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF		0x400
160773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF		0x800
161773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE		0x1000
162773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE		0x2000
163773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE		0x4000
164773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
165773642d9SDouglas Gilbert 			      SDEBUG_OPT_RESET_NOISE)
166773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
167773642d9SDouglas Gilbert 				  SDEBUG_OPT_TRANSPORT_ERR | \
168773642d9SDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
169773642d9SDouglas Gilbert 				  SDEBUG_OPT_SHORT_TRANSFER)
1701da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
171fd32119bSDouglas Gilbert  *   - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
1721da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
173773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_RECOVERED_ERR is set.
1746f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
175773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_TRANSPORT_ERR is set.
1761da177e4SLinus Torvalds  *
1771da177e4SLinus Torvalds  * When "every_nth" < 0 then after "- every_nth" commands:
178fd32119bSDouglas Gilbert  *   - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
1791da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
180773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_RECOVERED_ERR is set.
1816f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
182773642d9SDouglas Gilbert  *     commands if _DEBUG_OPT_TRANSPORT_ERR is set.
183773642d9SDouglas Gilbert  * This will continue on every subsequent command until some other action
184773642d9SDouglas Gilbert  * occurs (e.g. the user * writing a new value (other than -1 or 1) to
185773642d9SDouglas Gilbert  * every_nth via sysfs).
1861da177e4SLinus Torvalds  */
1871da177e4SLinus Torvalds 
188cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
189cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
190cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
191cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
192cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
193cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1
194cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2
1950d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3
19619c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4
197acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5	/* simulate firmware change */
198acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
199acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7
200cbf67842SDouglas Gilbert 
201773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
2021da177e4SLinus Torvalds  * sector on read commands: */
2031da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
20432f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2051da177e4SLinus Torvalds 
2061da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
2071da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
2081da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
2091da177e4SLinus Torvalds 
210c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
211c4837394SDouglas Gilbert  * (for response) per submit queue at one time. Can be reduced by max_queue
212c4837394SDouglas Gilbert  * option. Command responses are not queued when jdelay=0 and ndelay=0. The
213c4837394SDouglas Gilbert  * per-device DEF_CMD_PER_LUN can be changed via sysfs:
214c4837394SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
215c4837394SDouglas Gilbert  * but cannot exceed SDEBUG_CANQUEUE .
216c4837394SDouglas Gilbert  */
217c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS  3	/* a WORD is bits in a long */
218c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE  (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
219cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN  255
220cbf67842SDouglas Gilbert 
221fd32119bSDouglas Gilbert #define F_D_IN			1
222fd32119bSDouglas Gilbert #define F_D_OUT			2
223fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
224fd32119bSDouglas Gilbert #define F_D_UNKN		8
225fd32119bSDouglas Gilbert #define F_RL_WLUN_OK		0x10
226fd32119bSDouglas Gilbert #define F_SKIP_UA		0x20
227fd32119bSDouglas Gilbert #define F_DELAY_OVERR		0x40
228fd32119bSDouglas Gilbert #define F_SA_LOW		0x80	/* cdb byte 1, bits 4 to 0 */
229fd32119bSDouglas Gilbert #define F_SA_HIGH		0x100	/* as used by variable length cdbs */
230fd32119bSDouglas Gilbert #define F_INV_OP		0x200
231fd32119bSDouglas Gilbert #define F_FAKE_RW		0x400
232fd32119bSDouglas Gilbert #define F_M_ACCESS		0x800	/* media access */
233fd32119bSDouglas Gilbert 
234fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
235fd32119bSDouglas Gilbert #define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW)
236fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
237fd32119bSDouglas Gilbert 
238fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4
239fd32119bSDouglas Gilbert 
240b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32
241fd32119bSDouglas Gilbert 
242fd32119bSDouglas Gilbert 
243fd32119bSDouglas Gilbert struct sdebug_dev_info {
244fd32119bSDouglas Gilbert 	struct list_head dev_list;
245fd32119bSDouglas Gilbert 	unsigned int channel;
246fd32119bSDouglas Gilbert 	unsigned int target;
247fd32119bSDouglas Gilbert 	u64 lun;
248bf476433SChristoph Hellwig 	uuid_t lu_name;
249fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
250fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
251fd32119bSDouglas Gilbert 	atomic_t num_in_q;
252c4837394SDouglas Gilbert 	atomic_t stopped;
253fd32119bSDouglas Gilbert 	bool used;
254fd32119bSDouglas Gilbert };
255fd32119bSDouglas Gilbert 
256fd32119bSDouglas Gilbert struct sdebug_host_info {
257fd32119bSDouglas Gilbert 	struct list_head host_list;
258fd32119bSDouglas Gilbert 	struct Scsi_Host *shost;
259fd32119bSDouglas Gilbert 	struct device dev;
260fd32119bSDouglas Gilbert 	struct list_head dev_info_list;
261fd32119bSDouglas Gilbert };
262fd32119bSDouglas Gilbert 
263fd32119bSDouglas Gilbert #define to_sdebug_host(d)	\
264fd32119bSDouglas Gilbert 	container_of(d, struct sdebug_host_info, dev)
265fd32119bSDouglas Gilbert 
266fd32119bSDouglas Gilbert struct sdebug_defer {
267fd32119bSDouglas Gilbert 	struct hrtimer hrt;
268fd32119bSDouglas Gilbert 	struct execute_work ew;
269c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
270c4837394SDouglas Gilbert 	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
271c4837394SDouglas Gilbert 	int issuing_cpu;
272fd32119bSDouglas Gilbert };
273fd32119bSDouglas Gilbert 
274fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
275c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
276c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
277c4837394SDouglas Gilbert 	 */
278fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
279fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
280c4837394SDouglas Gilbert 	unsigned int inj_recovered:1;
281c4837394SDouglas Gilbert 	unsigned int inj_transport:1;
282c4837394SDouglas Gilbert 	unsigned int inj_dif:1;
283c4837394SDouglas Gilbert 	unsigned int inj_dix:1;
284c4837394SDouglas Gilbert 	unsigned int inj_short:1;
285fd32119bSDouglas Gilbert };
286fd32119bSDouglas Gilbert 
287c4837394SDouglas Gilbert struct sdebug_queue {
288c4837394SDouglas Gilbert 	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
289c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
290c4837394SDouglas Gilbert 	spinlock_t qc_lock;
291c4837394SDouglas Gilbert 	atomic_t blocked;	/* to temporarily stop more being queued */
292fd32119bSDouglas Gilbert };
293fd32119bSDouglas Gilbert 
294c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
295c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
296c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
297c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
298c4837394SDouglas Gilbert 
299fd32119bSDouglas Gilbert struct opcode_info_t {
300b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
301b01f6f83SDouglas Gilbert 				/* for terminating element */
302fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
303fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
304fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
305fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
306fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
307fd32119bSDouglas Gilbert 	u8 len_mask[16];	/* len=len_mask[0], then mask for cdb[1]... */
308fd32119bSDouglas Gilbert 				/* ignore cdb bytes after position 15 */
309fd32119bSDouglas Gilbert };
310fd32119bSDouglas Gilbert 
311fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
312c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
313c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
314c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
315c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
316c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
317c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
318c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
319c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
320c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
321c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
322c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
323c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
324c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
325c2248fc9SDouglas Gilbert 	SDEB_I_SERV_ACT_IN = 12,	/* 12, 16 */
326c2248fc9SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT = 13,	/* 12, 16 */
327c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
328c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
329c2248fc9SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* 10 only */
330c2248fc9SDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,
331c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
332c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
333c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
334c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
335c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
336c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
337c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
338c2248fc9SDouglas Gilbert 	SDEB_I_XDWRITEREAD = 25,	/* 10 only */
339c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_BUFFER = 26,
340c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_SAME = 27,		/* 10, 16 */
341c2248fc9SDouglas Gilbert 	SDEB_I_SYNC_CACHE = 28,		/* 10 only */
342c2248fc9SDouglas Gilbert 	SDEB_I_COMP_WRITE = 29,
343c2248fc9SDouglas Gilbert 	SDEB_I_LAST_ELEMENT = 30,	/* keep this last */
344c2248fc9SDouglas Gilbert };
345c2248fc9SDouglas Gilbert 
346c4837394SDouglas Gilbert 
347c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
348c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
349c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
350c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
351c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
352c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
353c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
354c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
355c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
356c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
357c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
358c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
359c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
360c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
361c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
362c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
363c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
364c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
365c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
366c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
367fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
368c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
369c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
370c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
371c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
372c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
373c2248fc9SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
374c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
375c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT,
376c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
377c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
378c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
379c2248fc9SDouglas Gilbert 	SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN,
380c2248fc9SDouglas Gilbert 	     0, 0, 0, 0,
381c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
382c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
383c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
384c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
385c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
386c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
387c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
388c2248fc9SDouglas Gilbert };
389c2248fc9SDouglas Gilbert 
390c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
391c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
392c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
393c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
394c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
395c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
396c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
397c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
398c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
399c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
400c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
401c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
402c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
403c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
40438d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
40538d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
406c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
407c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
408c2248fc9SDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
40938d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
410acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
411c2248fc9SDouglas Gilbert 
412c2248fc9SDouglas Gilbert static const struct opcode_info_t msense_iarr[1] = {
413c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
414c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
415c2248fc9SDouglas Gilbert };
416c2248fc9SDouglas Gilbert 
417c2248fc9SDouglas Gilbert static const struct opcode_info_t mselect_iarr[1] = {
418c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
419c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
420c2248fc9SDouglas Gilbert };
421c2248fc9SDouglas Gilbert 
422c2248fc9SDouglas Gilbert static const struct opcode_info_t read_iarr[3] = {
423c2248fc9SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */
424c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
425c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
426c2248fc9SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */
427c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
428c2248fc9SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */
429c2248fc9SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
430c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
431c2248fc9SDouglas Gilbert };
432c2248fc9SDouglas Gilbert 
433c2248fc9SDouglas Gilbert static const struct opcode_info_t write_iarr[3] = {
434c2248fc9SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,   /* 10 */
435c2248fc9SDouglas Gilbert 	    {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
436c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
437c2248fc9SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,    /* 6 */
438c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
439c2248fc9SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,   /* 12 */
440c2248fc9SDouglas Gilbert 	    {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
441c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
442c2248fc9SDouglas Gilbert };
443c2248fc9SDouglas Gilbert 
444c2248fc9SDouglas Gilbert static const struct opcode_info_t sa_in_iarr[1] = {
445c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
446c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
447c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },
448c2248fc9SDouglas Gilbert };
449c2248fc9SDouglas Gilbert 
450c2248fc9SDouglas Gilbert static const struct opcode_info_t vl_iarr[1] = {	/* VARIABLE LENGTH */
451c2248fc9SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0,
452c2248fc9SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa,
453c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
454c2248fc9SDouglas Gilbert };
455c2248fc9SDouglas Gilbert 
456c2248fc9SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[2] = {
45738d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
458c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
459c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
46038d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
461c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
462c2248fc9SDouglas Gilbert 	     0, 0} },
463c2248fc9SDouglas Gilbert };
464c2248fc9SDouglas Gilbert 
465c2248fc9SDouglas Gilbert static const struct opcode_info_t write_same_iarr[1] = {
466c2248fc9SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL,
467c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
468c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x1f, 0xc7} },
469c2248fc9SDouglas Gilbert };
470c2248fc9SDouglas Gilbert 
471c2248fc9SDouglas Gilbert static const struct opcode_info_t reserve_iarr[1] = {
472c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,	/* RESERVE(6) */
473c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
474c2248fc9SDouglas Gilbert };
475c2248fc9SDouglas Gilbert 
476c2248fc9SDouglas Gilbert static const struct opcode_info_t release_iarr[1] = {
477c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,	/* RELEASE(6) */
478c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
479c2248fc9SDouglas Gilbert };
480c2248fc9SDouglas Gilbert 
481c2248fc9SDouglas Gilbert 
482c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
483c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
484c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
485c2248fc9SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
486c2248fc9SDouglas Gilbert /* 0 */
487c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,
488c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
489c2248fc9SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL,
490c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
491c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
492c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
493c2248fc9SDouglas Gilbert 	     0, 0} },
494c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
495c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
496c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
497c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
498c2248fc9SDouglas Gilbert 	{1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr,
499c2248fc9SDouglas Gilbert 	    {10,  0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
500c2248fc9SDouglas Gilbert 	     0} },
501c2248fc9SDouglas Gilbert 	{1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr,
502c2248fc9SDouglas Gilbert 	    {10,  0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
503c2248fc9SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,
504c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
505c2248fc9SDouglas Gilbert 	     0, 0, 0} },
506c2248fc9SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,
507c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
508c2248fc9SDouglas Gilbert 	     0, 0} },
509c2248fc9SDouglas Gilbert 	{3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr,
510c2248fc9SDouglas Gilbert 	    {16,  0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
511c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x9f, 0xc7} },		/* READ(16) */
512c2248fc9SDouglas Gilbert /* 10 */
513c2248fc9SDouglas Gilbert 	{3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr,
514c2248fc9SDouglas Gilbert 	    {16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
515c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x9f, 0xc7} },		/* WRITE(16) */
516c2248fc9SDouglas Gilbert 	{0, 0x1b, 0, 0, resp_start_stop, NULL,		/* START STOP UNIT */
517c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
518c2248fc9SDouglas Gilbert 	{1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr,
519c2248fc9SDouglas Gilbert 	    {16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
520c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x1, 0xc7} },	/* READ CAPACITY(16) */
521c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */
522c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
523c2248fc9SDouglas Gilbert 	{2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr,
524c2248fc9SDouglas Gilbert 	    {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0,
525c2248fc9SDouglas Gilbert 	     0} },
526c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
527c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
528f7f9f26bSDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */
529f7f9f26bSDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
530f7f9f26bSDouglas Gilbert 	     0, 0, 0, 0, 0, 0} },
531c2248fc9SDouglas Gilbert 	{1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0,
532c2248fc9SDouglas Gilbert 	    vl_iarr, {32,  0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0,
533c2248fc9SDouglas Gilbert 		      0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */
534c2248fc9SDouglas Gilbert 	{1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */
535c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
536c2248fc9SDouglas Gilbert 	     0} },
537c2248fc9SDouglas Gilbert 	{1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */
538c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
539c2248fc9SDouglas Gilbert 	     0} },
540c2248fc9SDouglas Gilbert /* 20 */
541f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
542f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
543c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
544c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
545c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
546c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
547c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
548c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
549c2248fc9SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */
550c2248fc9SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
551c2248fc9SDouglas Gilbert 	{0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10,
552c2248fc9SDouglas Gilbert 	    NULL, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7,
553c2248fc9SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
554acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
555acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
556acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
557c2248fc9SDouglas Gilbert 	{1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10,
558c2248fc9SDouglas Gilbert 	    write_same_iarr, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff,
559c2248fc9SDouglas Gilbert 			      0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
560c2248fc9SDouglas Gilbert 	{0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */
561c2248fc9SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
562c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
56338d5c833SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL,
564c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
565c2248fc9SDouglas Gilbert 	     0, 0xff, 0x1f, 0xc7} },		/* COMPARE AND WRITE */
566c2248fc9SDouglas Gilbert 
567c2248fc9SDouglas Gilbert /* 30 */
568c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
569c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
570c2248fc9SDouglas Gilbert };
571c2248fc9SDouglas Gilbert 
572773642d9SDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;
573773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
574c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
575773642d9SDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
576773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
577773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
578773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
579773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
580773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
581773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
582773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
583773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
584c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
585cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
586c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
587773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
588773642d9SDouglas Gilbert static int sdebug_no_uld;
589773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
590773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
591773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
592773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
593773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
59486e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
595b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
596773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
597773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
598773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
599773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
600773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
601773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
602773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
603773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
604773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
605773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
606773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
607773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
608773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
60909ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
610773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
611773642d9SDouglas Gilbert static bool sdebug_clustering;
612773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
613773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
614817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
615773642d9SDouglas Gilbert static bool sdebug_verbose;
616f46eb0e9SDouglas Gilbert static bool have_dif_prot;
617c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
618c4837394SDouglas Gilbert static bool sdebug_mq_active;
6191da177e4SLinus Torvalds 
620c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
6211da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
6221da177e4SLinus Torvalds 
6231da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
6241da177e4SLinus Torvalds    may still need them */
6251da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
6261da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
6271da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
6281da177e4SLinus Torvalds 
6291da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
6301da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
6311da177e4SLinus Torvalds 
6321da177e4SLinus Torvalds static unsigned char *fake_storep;	/* ramdisk storage */
6336ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_storep;	/* protection info */
63444d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
6351da177e4SLinus Torvalds 
63644d92694SMartin K. Petersen static unsigned long map_size;
637cbf67842SDouglas Gilbert static int num_aborts;
638cbf67842SDouglas Gilbert static int num_dev_resets;
639cbf67842SDouglas Gilbert static int num_target_resets;
640cbf67842SDouglas Gilbert static int num_bus_resets;
641cbf67842SDouglas Gilbert static int num_host_resets;
642c6a44287SMartin K. Petersen static int dix_writes;
643c6a44287SMartin K. Petersen static int dix_reads;
644c6a44287SMartin K. Petersen static int dif_errors;
6451da177e4SLinus Torvalds 
646c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
647c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
648fd32119bSDouglas Gilbert 
6491da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
6501da177e4SLinus Torvalds 
651cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
652cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
6531da177e4SLinus Torvalds 
6541da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
6551da177e4SLinus Torvalds 
6561da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
6571da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
6581da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
6591da177e4SLinus Torvalds };
6601da177e4SLinus Torvalds 
6611da177e4SLinus Torvalds static const int check_condition_result =
6621da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
6631da177e4SLinus Torvalds 
664c6a44287SMartin K. Petersen static const int illegal_condition_result =
665c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
666c6a44287SMartin K. Petersen 
667cbf67842SDouglas Gilbert static const int device_qfull_result =
668cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
669cbf67842SDouglas Gilbert 
670fd32119bSDouglas Gilbert 
671760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
672760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
673760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
674760f3b03SDouglas Gilbert  */
675760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
676fd32119bSDouglas Gilbert {
677fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
678fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
679fd32119bSDouglas Gilbert }
680c65b1445SDouglas Gilbert 
68114faa944SAkinobu Mita static void *fake_store(unsigned long long lba)
68214faa944SAkinobu Mita {
68314faa944SAkinobu Mita 	lba = do_div(lba, sdebug_store_sectors);
68414faa944SAkinobu Mita 
685773642d9SDouglas Gilbert 	return fake_storep + lba * sdebug_sector_size;
68614faa944SAkinobu Mita }
68714faa944SAkinobu Mita 
6886ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_store(sector_t sector)
68914faa944SAkinobu Mita {
69049413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
69114faa944SAkinobu Mita 
69214faa944SAkinobu Mita 	return dif_storep + sector;
69314faa944SAkinobu Mita }
69414faa944SAkinobu Mita 
6958dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
6968dea0d02SFUJITA Tomonori {
6978dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
6988dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
6998dea0d02SFUJITA Tomonori 
7008dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
7018dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
7028dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
7038dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
704773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
705773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
7068dea0d02SFUJITA Tomonori 		else
707773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
708773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
709f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
7108dea0d02SFUJITA Tomonori 	}
7118dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
7128dea0d02SFUJITA Tomonori }
7138dea0d02SFUJITA Tomonori 
71422017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
71522017ed2SDouglas Gilbert 
71622017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
717fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
718fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
71922017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
72022017ed2SDouglas Gilbert {
72122017ed2SDouglas Gilbert 	unsigned char *sbuff;
72222017ed2SDouglas Gilbert 	u8 sks[4];
72322017ed2SDouglas Gilbert 	int sl, asc;
72422017ed2SDouglas Gilbert 
72522017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
72622017ed2SDouglas Gilbert 	if (!sbuff) {
72722017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
72822017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
72922017ed2SDouglas Gilbert 		return;
73022017ed2SDouglas Gilbert 	}
73122017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
73222017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
733773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
73422017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
73522017ed2SDouglas Gilbert 	sks[0] = 0x80;
73622017ed2SDouglas Gilbert 	if (c_d)
73722017ed2SDouglas Gilbert 		sks[0] |= 0x40;
73822017ed2SDouglas Gilbert 	if (in_bit >= 0) {
73922017ed2SDouglas Gilbert 		sks[0] |= 0x8;
74022017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
74122017ed2SDouglas Gilbert 	}
74222017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
743773642d9SDouglas Gilbert 	if (sdebug_dsense) {
74422017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
74522017ed2SDouglas Gilbert 		sbuff[7] = sl;
74622017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
74722017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
74822017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
74922017ed2SDouglas Gilbert 	} else
75022017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
751773642d9SDouglas Gilbert 	if (sdebug_verbose)
75222017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
75322017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
75422017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
75522017ed2SDouglas Gilbert }
75622017ed2SDouglas Gilbert 
757cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
7588dea0d02SFUJITA Tomonori {
7598dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
7608dea0d02SFUJITA Tomonori 
761cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
762cbf67842SDouglas Gilbert 	if (!sbuff) {
763cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
764cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
765cbf67842SDouglas Gilbert 		return;
766cbf67842SDouglas Gilbert 	}
767cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
7688dea0d02SFUJITA Tomonori 
769773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
7708dea0d02SFUJITA Tomonori 
771773642d9SDouglas Gilbert 	if (sdebug_verbose)
772cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
773cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
774cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
7758dea0d02SFUJITA Tomonori }
7761da177e4SLinus Torvalds 
777fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
77822017ed2SDouglas Gilbert {
77922017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
78022017ed2SDouglas Gilbert }
78122017ed2SDouglas Gilbert 
7821da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
7831da177e4SLinus Torvalds {
784773642d9SDouglas Gilbert 	if (sdebug_verbose) {
785cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
786cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
787cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
788cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
789cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
790cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
791cbf67842SDouglas Gilbert 				    __func__);
792cbf67842SDouglas Gilbert 		else
793cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
794cbf67842SDouglas Gilbert 				    __func__, cmd);
7951da177e4SLinus Torvalds 	}
7961da177e4SLinus Torvalds 	return -EINVAL;
7971da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
7981da177e4SLinus Torvalds }
7991da177e4SLinus Torvalds 
80019c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
80119c8ead7SEwan D. Milne {
80219c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
80319c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
80419c8ead7SEwan D. Milne 
80519c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
80619c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
80719c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
80819c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
80919c8ead7SEwan D. Milne 			    (devip->target == dp->target))
81019c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
81119c8ead7SEwan D. Milne 		}
81219c8ead7SEwan D. Milne 	}
81319c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
81419c8ead7SEwan D. Milne }
81519c8ead7SEwan D. Milne 
816f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
8171da177e4SLinus Torvalds {
818cbf67842SDouglas Gilbert 	int k;
819cbf67842SDouglas Gilbert 
820cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
821cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
822cbf67842SDouglas Gilbert 		const char *cp = NULL;
823cbf67842SDouglas Gilbert 
824cbf67842SDouglas Gilbert 		switch (k) {
825cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
826f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
827f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
828773642d9SDouglas Gilbert 			if (sdebug_verbose)
829cbf67842SDouglas Gilbert 				cp = "power on reset";
830cbf67842SDouglas Gilbert 			break;
831cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
832f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
833f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
834773642d9SDouglas Gilbert 			if (sdebug_verbose)
835cbf67842SDouglas Gilbert 				cp = "bus reset";
836cbf67842SDouglas Gilbert 			break;
837cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
838f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
839f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
840773642d9SDouglas Gilbert 			if (sdebug_verbose)
841cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
842cbf67842SDouglas Gilbert 			break;
8430d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
844f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
845f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
846773642d9SDouglas Gilbert 			if (sdebug_verbose)
8470d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
848f49accf1SEwan D. Milne 			break;
849acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
850f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
851b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
852b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
853773642d9SDouglas Gilbert 			if (sdebug_verbose)
854acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
855acafd0b9SEwan D. Milne 			break;
856acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
857f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
858acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
859acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
860773642d9SDouglas Gilbert 			if (sdebug_verbose)
861acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
862acafd0b9SEwan D. Milne 			break;
86319c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
86419c8ead7SEwan D. Milne 			/*
86519c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
86619c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
86719c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
86819c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
869773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
87019c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
87119c8ead7SEwan D. Milne 			 */
872773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
87319c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
874f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
87519c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
87619c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
877773642d9SDouglas Gilbert 			if (sdebug_verbose)
87819c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
87919c8ead7SEwan D. Milne 			break;
880cbf67842SDouglas Gilbert 		default:
881773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
882773642d9SDouglas Gilbert 			if (sdebug_verbose)
883cbf67842SDouglas Gilbert 				cp = "unknown";
884cbf67842SDouglas Gilbert 			break;
885cbf67842SDouglas Gilbert 		}
886cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
887773642d9SDouglas Gilbert 		if (sdebug_verbose)
888f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
889cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
890cbf67842SDouglas Gilbert 				   my_name, cp);
8911da177e4SLinus Torvalds 		return check_condition_result;
8921da177e4SLinus Torvalds 	}
8931da177e4SLinus Torvalds 	return 0;
8941da177e4SLinus Torvalds }
8951da177e4SLinus Torvalds 
896fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
8971da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
8981da177e4SLinus Torvalds 				int arr_len)
8991da177e4SLinus Torvalds {
90021a61829SFUJITA Tomonori 	int act_len;
901072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
9021da177e4SLinus Torvalds 
903072d0bb3SFUJITA Tomonori 	if (!sdb->length)
9041da177e4SLinus Torvalds 		return 0;
905072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
906773642d9SDouglas Gilbert 		return DID_ERROR << 16;
90721a61829SFUJITA Tomonori 
90821a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
90921a61829SFUJITA Tomonori 				      arr, arr_len);
91021a61829SFUJITA Tomonori 	sdb->resid = scsi_bufflen(scp) - act_len;
91121a61829SFUJITA Tomonori 
9121da177e4SLinus Torvalds 	return 0;
9131da177e4SLinus Torvalds }
9141da177e4SLinus Torvalds 
915fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
916fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
917fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
918fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
919fb0cc8d1SDouglas Gilbert  */
920fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
921fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
922fb0cc8d1SDouglas Gilbert {
923fb0cc8d1SDouglas Gilbert 	int act_len, n;
924fb0cc8d1SDouglas Gilbert 	struct scsi_data_buffer *sdb = scsi_in(scp);
925fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
926fb0cc8d1SDouglas Gilbert 
927fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
928fb0cc8d1SDouglas Gilbert 		return 0;
929fb0cc8d1SDouglas Gilbert 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
930fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
931fb0cc8d1SDouglas Gilbert 
932fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
933fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
934fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
935fb0cc8d1SDouglas Gilbert 		 __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid);
936fb0cc8d1SDouglas Gilbert 	n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
937fb0cc8d1SDouglas Gilbert 	sdb->resid = min(sdb->resid, n);
938fb0cc8d1SDouglas Gilbert 	return 0;
939fb0cc8d1SDouglas Gilbert }
940fb0cc8d1SDouglas Gilbert 
941fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
942fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
943fb0cc8d1SDouglas Gilbert  */
9441da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
94521a61829SFUJITA Tomonori 			       int arr_len)
9461da177e4SLinus Torvalds {
94721a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
9481da177e4SLinus Torvalds 		return 0;
949072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
9501da177e4SLinus Torvalds 		return -1;
95121a61829SFUJITA Tomonori 
95221a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
9531da177e4SLinus Torvalds }
9541da177e4SLinus Torvalds 
9551da177e4SLinus Torvalds 
956e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux   ";
957e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug      ";
958e5203cf0SHannes Reinecke static char sdebug_inq_product_rev[5] = "0186";	/* version less '.' */
9591b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
9601b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
9611b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
9621b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
9631da177e4SLinus Torvalds 
964cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
965760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
9665a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
96709ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
968bf476433SChristoph Hellwig 			  const uuid_t *lu_name)
9691da177e4SLinus Torvalds {
970c65b1445SDouglas Gilbert 	int num, port_a;
971c65b1445SDouglas Gilbert 	char b[32];
9721da177e4SLinus Torvalds 
973c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
9741da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
9751da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
9761da177e4SLinus Torvalds 	arr[1] = 0x1;
9771da177e4SLinus Torvalds 	arr[2] = 0x0;
978e5203cf0SHannes Reinecke 	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
979e5203cf0SHannes Reinecke 	memcpy(&arr[12], sdebug_inq_product_id, 16);
9801da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
9811da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
9821da177e4SLinus Torvalds 	arr[3] = num;
9831da177e4SLinus Torvalds 	num += 4;
984c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
98509ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
98609ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
98709ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
98809ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
98909ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
99009ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
99109ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
99209ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
99309ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
99409ba24c1SDouglas Gilbert 			num += 16;
99509ba24c1SDouglas Gilbert 		} else {
9961b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
997c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
998c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
999c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
1000c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
10011b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1002773642d9SDouglas Gilbert 			num += 8;
100309ba24c1SDouglas Gilbert 		}
1004c65b1445SDouglas Gilbert 		/* Target relative port number */
1005c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1006c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1007c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1008c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1009c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1010c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1011c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1012c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1013c65b1445SDouglas Gilbert 	}
10141b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1015c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1016c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1017c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1018c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
10191b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1020773642d9SDouglas Gilbert 	num += 8;
10211b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
10225a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
10235a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
10245a09e398SHannes Reinecke 	arr[num++] = 0x0;
10255a09e398SHannes Reinecke 	arr[num++] = 0x4;
10265a09e398SHannes Reinecke 	arr[num++] = 0;
10275a09e398SHannes Reinecke 	arr[num++] = 0;
1028773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1029773642d9SDouglas Gilbert 	num += 2;
10301b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1031c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1032c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1033c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1034c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
10351b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1036773642d9SDouglas Gilbert 	num += 8;
1037c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1038c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1039c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1040c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1041c65b1445SDouglas Gilbert 	arr[num++] = 24;
10421b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1043c65b1445SDouglas Gilbert 	num += 12;
1044c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1045c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1046c65b1445SDouglas Gilbert 	num += 8;
1047c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1048c65b1445SDouglas Gilbert 	num += 4;
1049c65b1445SDouglas Gilbert 	return num;
1050c65b1445SDouglas Gilbert }
1051c65b1445SDouglas Gilbert 
1052c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1053c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1054c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1055c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1056c65b1445SDouglas Gilbert };
1057c65b1445SDouglas Gilbert 
1058cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1059760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1060c65b1445SDouglas Gilbert {
1061c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1062c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1063c65b1445SDouglas Gilbert }
1064c65b1445SDouglas Gilbert 
1065cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1066760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1067c65b1445SDouglas Gilbert {
1068c65b1445SDouglas Gilbert 	int num = 0;
1069c65b1445SDouglas Gilbert 	const char * na1 = "https://www.kernel.org/config";
1070c65b1445SDouglas Gilbert 	const char * na2 = "http://www.kernel.org/log";
1071c65b1445SDouglas Gilbert 	int plen, olen;
1072c65b1445SDouglas Gilbert 
1073c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1074c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1075c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1076c65b1445SDouglas Gilbert 	olen = strlen(na1);
1077c65b1445SDouglas Gilbert 	plen = olen + 1;
1078c65b1445SDouglas Gilbert 	if (plen % 4)
1079c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1080c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1081c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1082c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1083c65b1445SDouglas Gilbert 	num += plen;
1084c65b1445SDouglas Gilbert 
1085c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1086c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1087c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1088c65b1445SDouglas Gilbert 	olen = strlen(na2);
1089c65b1445SDouglas Gilbert 	plen = olen + 1;
1090c65b1445SDouglas Gilbert 	if (plen % 4)
1091c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1092c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1093c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1094c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1095c65b1445SDouglas Gilbert 	num += plen;
1096c65b1445SDouglas Gilbert 
1097c65b1445SDouglas Gilbert 	return num;
1098c65b1445SDouglas Gilbert }
1099c65b1445SDouglas Gilbert 
1100c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1101760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1102c65b1445SDouglas Gilbert {
1103c65b1445SDouglas Gilbert 	int num = 0;
1104c65b1445SDouglas Gilbert 	int port_a, port_b;
1105c65b1445SDouglas Gilbert 
1106c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1107c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1108c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1109c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1110c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1111c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1112c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1113c65b1445SDouglas Gilbert 	num += 6;
1114c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1115c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1116c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1117c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1118c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1119c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1120c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
11211b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1122773642d9SDouglas Gilbert 	num += 8;
1123c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1124c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1125c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1126c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1127c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1128c65b1445SDouglas Gilbert 	num += 6;
1129c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1130c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1131c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1132c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1133c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1134c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1135c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
11361b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1137773642d9SDouglas Gilbert 	num += 8;
1138c65b1445SDouglas Gilbert 
1139c65b1445SDouglas Gilbert 	return num;
1140c65b1445SDouglas Gilbert }
1141c65b1445SDouglas Gilbert 
1142c65b1445SDouglas Gilbert 
1143c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1144c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1145c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1146c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1147c65b1445SDouglas Gilbert '1','2','3','4',
1148c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1149c65b1445SDouglas Gilbert 0xec,0,0,0,
1150c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1151c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1152c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1153c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1154c65b1445SDouglas Gilbert 0x53,0x41,
1155c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1156c65b1445SDouglas Gilbert 0x20,0x20,
1157c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1158c65b1445SDouglas Gilbert 0x10,0x80,
1159c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1160c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1161c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1162c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1163c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1164c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1165c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1166c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1167c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1168c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1169c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1170c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1171c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1172c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1173c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1174c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1175c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1176c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1177c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1178c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1179c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1180c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1181c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1182c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1183c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1184c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1185c65b1445SDouglas Gilbert };
1186c65b1445SDouglas Gilbert 
1187cbf67842SDouglas Gilbert /* ATA Information VPD page */
1188760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1189c65b1445SDouglas Gilbert {
1190c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1191c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1192c65b1445SDouglas Gilbert }
1193c65b1445SDouglas Gilbert 
1194c65b1445SDouglas Gilbert 
1195c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
11961e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
11971e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11981e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11991e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1200c65b1445SDouglas Gilbert };
1201c65b1445SDouglas Gilbert 
1202cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1203760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1204c65b1445SDouglas Gilbert {
1205ea61fca5SMartin K. Petersen 	unsigned int gran;
1206ea61fca5SMartin K. Petersen 
1207c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1208e308b3d1SMartin K. Petersen 
1209e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
121086e6828aSLukas Herbolt 	if (sdebug_opt_xferlen_exp != 0 &&
121186e6828aSLukas Herbolt 	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
121286e6828aSLukas Herbolt 		gran = 1 << sdebug_opt_xferlen_exp;
121386e6828aSLukas Herbolt 	else
1214773642d9SDouglas Gilbert 		gran = 1 << sdebug_physblk_exp;
1215773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1216e308b3d1SMartin K. Petersen 
1217e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1218773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1219773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
122044d92694SMartin K. Petersen 
1221e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1222773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1223e308b3d1SMartin K. Petersen 
1224773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1225e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1226773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1227e308b3d1SMartin K. Petersen 
1228e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1229773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
123044d92694SMartin K. Petersen 	}
123144d92694SMartin K. Petersen 
1232e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1233773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1234773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
123544d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
123644d92694SMartin K. Petersen 	}
123744d92694SMartin K. Petersen 
1238e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1239773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
12406014759cSMartin K. Petersen 
12415b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1242773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
12435b94e232SMartin K. Petersen 
12445b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
124544d92694SMartin K. Petersen 
1246c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
12471da177e4SLinus Torvalds }
12481da177e4SLinus Torvalds 
12491e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
1250760f3b03SDouglas Gilbert static int inquiry_vpd_b1(unsigned char *arr)
1251eac6e8e4SMatthew Wilcox {
1252eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1253eac6e8e4SMatthew Wilcox 	arr[0] = 0;
12541e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
12551e49f785SDouglas Gilbert 	arr[2] = 0;
12561e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
1257eac6e8e4SMatthew Wilcox 
1258eac6e8e4SMatthew Wilcox 	return 0x3c;
1259eac6e8e4SMatthew Wilcox }
12601da177e4SLinus Torvalds 
1261760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1262760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
12636014759cSMartin K. Petersen {
12643f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
12656014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1266773642d9SDouglas Gilbert 	if (sdebug_lbpu)
12676014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1268773642d9SDouglas Gilbert 	if (sdebug_lbpws)
12696014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1270773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
12715b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1272760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1273760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1274760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1275760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1276760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
12773f0bc3b3SMartin K. Petersen 	return 0x4;
12786014759cSMartin K. Petersen }
12796014759cSMartin K. Petersen 
12801da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1281c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
12821da177e4SLinus Torvalds 
1283c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
12841da177e4SLinus Torvalds {
12851da177e4SLinus Torvalds 	unsigned char pq_pdt;
12865a09e398SHannes Reinecke 	unsigned char * arr;
128701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
12885a09e398SHannes Reinecke 	int alloc_len, n, ret;
1289760f3b03SDouglas Gilbert 	bool have_wlun, is_disk;
12901da177e4SLinus Torvalds 
1291773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
12926f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
12936f3cbf55SDouglas Gilbert 	if (! arr)
12946f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1295760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
1296b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1297c2248fc9SDouglas Gilbert 	if (have_wlun)
1298b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1299b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1300b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1301c65b1445SDouglas Gilbert 	else
1302773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
13031da177e4SLinus Torvalds 	arr[0] = pq_pdt;
13041da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
130522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
13065a09e398SHannes Reinecke 		kfree(arr);
13071da177e4SLinus Torvalds 		return check_condition_result;
13081da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
13095a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1310c65b1445SDouglas Gilbert 		char lu_id_str[6];
1311c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
13121da177e4SLinus Torvalds 
13135a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
13145a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1315b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
131623183910SDouglas Gilbert 			host_no = 0;
1317c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1318c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1319c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1320c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1321c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
13221da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1323c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1324c65b1445SDouglas Gilbert 			n = 4;
1325c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1326c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1327c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1328c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1329c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1330c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1331c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1332c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1333760f3b03SDouglas Gilbert 			if (is_disk) {	  /* SBC only */
1334c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1335760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1336760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1337760f3b03SDouglas Gilbert 				arr[n++] = 0xb2;  /* Logical Block Prov */
1338760f3b03SDouglas Gilbert 			}
1339c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
13401da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1341c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
13421da177e4SLinus Torvalds 			arr[3] = len;
1343c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
13441da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1345c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1346760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
13475a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
134809ba24c1SDouglas Gilbert 						lu_id_str, len,
134909ba24c1SDouglas Gilbert 						&devip->lu_name);
1350c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1351c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1352760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1353c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1354c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1355760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1356c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1357c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1358c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
13598475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1360c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1361760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1362c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1363c6a44287SMartin K. Petersen 			else
1364c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1365c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1366c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1367c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1368c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1369c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1370c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1371c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1372c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1373c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1374c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1375760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1376760f3b03SDouglas Gilbert 		} else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
1377c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1378760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1379773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1380760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
1381c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1382760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1383760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
1384eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
1385760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b1(&arr[4]);
1386760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
13876014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1388760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
13891da177e4SLinus Torvalds 		} else {
139022017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
13915a09e398SHannes Reinecke 			kfree(arr);
13921da177e4SLinus Torvalds 			return check_condition_result;
13931da177e4SLinus Torvalds 		}
1394773642d9SDouglas Gilbert 		len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
13955a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1396c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
13975a09e398SHannes Reinecke 		kfree(arr);
13985a09e398SHannes Reinecke 		return ret;
13991da177e4SLinus Torvalds 	}
14001da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1401773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1402773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
14031da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
14041da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1405f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1406b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
140770bdf202SMartin K. Petersen 		arr[5] |= 0x10; /* claim: implicit TPGS */
1408c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
14091da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1410c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
1411e5203cf0SHannes Reinecke 	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1412e5203cf0SHannes Reinecke 	memcpy(&arr[16], sdebug_inq_product_id, 16);
1413e5203cf0SHannes Reinecke 	memcpy(&arr[32], sdebug_inq_product_rev, 4);
14141da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1415760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1416760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1417c65b1445SDouglas Gilbert 	n = 62;
1418760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1419760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1420760f3b03SDouglas Gilbert 		n += 2;
1421760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1422760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1423760f3b03SDouglas Gilbert 		n += 2;
14241da177e4SLinus Torvalds 	}
1425760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
14265a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
14271da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
14285a09e398SHannes Reinecke 	kfree(arr);
14295a09e398SHannes Reinecke 	return ret;
14301da177e4SLinus Torvalds }
14311da177e4SLinus Torvalds 
1432fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1433fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1434fd32119bSDouglas Gilbert 
14351da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp,
14361da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip)
14371da177e4SLinus Torvalds {
14381da177e4SLinus Torvalds 	unsigned char * sbuff;
143901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1440cbf67842SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
14412492fc09STomas Winkler 	bool dsense;
14421da177e4SLinus Torvalds 	int len = 18;
14431da177e4SLinus Torvalds 
1444c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1445c2248fc9SDouglas Gilbert 	dsense = !!(cmd[1] & 1);
1446cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
1447c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1448c2248fc9SDouglas Gilbert 		if (dsense) {
1449c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1450c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1451c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
1452c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
1453c2248fc9SDouglas Gilbert 			len = 8;
1454c65b1445SDouglas Gilbert 		} else {
1455c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1456c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1457c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1458c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
1459c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
1460c65b1445SDouglas Gilbert 		}
1461c65b1445SDouglas Gilbert 	} else {
1462cbf67842SDouglas Gilbert 		memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
1463773642d9SDouglas Gilbert 		if (arr[0] >= 0x70 && dsense == sdebug_dsense)
1464c2248fc9SDouglas Gilbert 			;	/* have sense and formats match */
1465c2248fc9SDouglas Gilbert 		else if (arr[0] <= 0x70) {
1466c2248fc9SDouglas Gilbert 			if (dsense) {
1467c2248fc9SDouglas Gilbert 				memset(arr, 0, 8);
1468c2248fc9SDouglas Gilbert 				arr[0] = 0x72;
1469c2248fc9SDouglas Gilbert 				len = 8;
1470c2248fc9SDouglas Gilbert 			} else {
1471c2248fc9SDouglas Gilbert 				memset(arr, 0, 18);
1472c2248fc9SDouglas Gilbert 				arr[0] = 0x70;
1473c2248fc9SDouglas Gilbert 				arr[7] = 0xa;
1474c2248fc9SDouglas Gilbert 			}
1475c2248fc9SDouglas Gilbert 		} else if (dsense) {
1476c2248fc9SDouglas Gilbert 			memset(arr, 0, 8);
14771da177e4SLinus Torvalds 			arr[0] = 0x72;
14781da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
14791da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
14801da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
14811da177e4SLinus Torvalds 			len = 8;
1482c2248fc9SDouglas Gilbert 		} else {
1483c2248fc9SDouglas Gilbert 			memset(arr, 0, 18);
1484c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1485c2248fc9SDouglas Gilbert 			arr[2] = sbuff[1];
1486c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1487c2248fc9SDouglas Gilbert 			arr[12] = sbuff[1];
1488c2248fc9SDouglas Gilbert 			arr[13] = sbuff[3];
1489c65b1445SDouglas Gilbert 		}
1490c2248fc9SDouglas Gilbert 
1491c65b1445SDouglas Gilbert 	}
1492cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
14931da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
14941da177e4SLinus Torvalds }
14951da177e4SLinus Torvalds 
1496c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp,
1497c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
1498c65b1445SDouglas Gilbert {
149901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1500c4837394SDouglas Gilbert 	int power_cond, stop;
1501c65b1445SDouglas Gilbert 
1502c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1503c65b1445SDouglas Gilbert 	if (power_cond) {
150422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1505c65b1445SDouglas Gilbert 		return check_condition_result;
1506c65b1445SDouglas Gilbert 	}
1507c4837394SDouglas Gilbert 	stop = !(cmd[4] & 1);
1508c4837394SDouglas Gilbert 	atomic_xchg(&devip->stopped, stop);
1509c65b1445SDouglas Gilbert 	return 0;
1510c65b1445SDouglas Gilbert }
1511c65b1445SDouglas Gilbert 
151228898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
151328898873SFUJITA Tomonori {
1514773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1515773642d9SDouglas Gilbert 
1516773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1517773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1518773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
151928898873SFUJITA Tomonori 	else
152028898873SFUJITA Tomonori 		return sdebug_store_sectors;
152128898873SFUJITA Tomonori }
152228898873SFUJITA Tomonori 
15231da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
15241da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp,
15251da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
15261da177e4SLinus Torvalds {
15271da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1528c65b1445SDouglas Gilbert 	unsigned int capac;
15291da177e4SLinus Torvalds 
1530c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
153128898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
15321da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1533c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1534c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1535773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1536773642d9SDouglas Gilbert 	} else
1537773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1538773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
15391da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
15401da177e4SLinus Torvalds }
15411da177e4SLinus Torvalds 
1542c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1543c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp,
1544c65b1445SDouglas Gilbert 			  struct sdebug_dev_info * devip)
1545c65b1445SDouglas Gilbert {
154601123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1547c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1548773642d9SDouglas Gilbert 	int alloc_len;
1549c65b1445SDouglas Gilbert 
1550773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1551c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
155228898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1553c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1554773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1555773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1556773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1557773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
155844d92694SMartin K. Petersen 
1559be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
15605b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1561760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1562760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1563760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1564760f3b03SDouglas Gilbert 		 */
1565760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1566760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1567be1dd78dSEric Sandeen 	}
156844d92694SMartin K. Petersen 
1569773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1570c6a44287SMartin K. Petersen 
1571760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1572773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1573c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1574c6a44287SMartin K. Petersen 	}
1575c6a44287SMartin K. Petersen 
1576c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1577c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1578c65b1445SDouglas Gilbert }
1579c65b1445SDouglas Gilbert 
15805a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
15815a09e398SHannes Reinecke 
15825a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp,
15835a09e398SHannes Reinecke 			      struct sdebug_dev_info * devip)
15845a09e398SHannes Reinecke {
158501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
15865a09e398SHannes Reinecke 	unsigned char * arr;
15875a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
15885a09e398SHannes Reinecke 	int n, ret, alen, rlen;
15895a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
15905a09e398SHannes Reinecke 
1591773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
15926f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
15936f3cbf55SDouglas Gilbert 	if (! arr)
15946f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
15955a09e398SHannes Reinecke 	/*
15965a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
15975a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
15985a09e398SHannes Reinecke 	 * So we create two port groups with one port each
15995a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
16005a09e398SHannes Reinecke 	 */
16015a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
16025a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
16035a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
16045a09e398SHannes Reinecke 			(devip->channel & 0x7f);
16055a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
16065a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
16075a09e398SHannes Reinecke 
16085a09e398SHannes Reinecke 	/*
16095a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
16105a09e398SHannes Reinecke 	 */
16115a09e398SHannes Reinecke 	n = 4;
1612b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
16135a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
16145a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
16155a09e398SHannes Reinecke 	} else {
16165a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1617773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
16185a09e398SHannes Reinecke 	}
1619773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1620773642d9SDouglas Gilbert 	n += 2;
16215a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
16225a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
16235a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
16245a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
16255a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
16265a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1627773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1628773642d9SDouglas Gilbert 	n += 2;
16295a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
16305a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1631773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1632773642d9SDouglas Gilbert 	n += 2;
16335a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
16345a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
16355a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
16365a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
16375a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
16385a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1639773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1640773642d9SDouglas Gilbert 	n += 2;
16415a09e398SHannes Reinecke 
16425a09e398SHannes Reinecke 	rlen = n - 4;
1643773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
16445a09e398SHannes Reinecke 
16455a09e398SHannes Reinecke 	/*
16465a09e398SHannes Reinecke 	 * Return the smallest value of either
16475a09e398SHannes Reinecke 	 * - The allocated length
16485a09e398SHannes Reinecke 	 * - The constructed command length
16495a09e398SHannes Reinecke 	 * - The maximum array size
16505a09e398SHannes Reinecke 	 */
16515a09e398SHannes Reinecke 	rlen = min(alen,n);
16525a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
16535a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
16545a09e398SHannes Reinecke 	kfree(arr);
16555a09e398SHannes Reinecke 	return ret;
16565a09e398SHannes Reinecke }
16575a09e398SHannes Reinecke 
1658fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1659fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
166038d5c833SDouglas Gilbert {
166138d5c833SDouglas Gilbert 	bool rctd;
166238d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
166338d5c833SDouglas Gilbert 	u16 req_sa, u;
166438d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
166538d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
166638d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
166738d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
166838d5c833SDouglas Gilbert 	u8 *arr;
166938d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
167038d5c833SDouglas Gilbert 
167138d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
167238d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
167338d5c833SDouglas Gilbert 	req_opcode = cmd[3];
167438d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
167538d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
16766d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
167738d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
167838d5c833SDouglas Gilbert 		return check_condition_result;
167938d5c833SDouglas Gilbert 	}
168038d5c833SDouglas Gilbert 	if (alloc_len > 8192)
168138d5c833SDouglas Gilbert 		a_len = 8192;
168238d5c833SDouglas Gilbert 	else
168338d5c833SDouglas Gilbert 		a_len = alloc_len;
168499531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
168538d5c833SDouglas Gilbert 	if (NULL == arr) {
168638d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
168738d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
168838d5c833SDouglas Gilbert 		return check_condition_result;
168938d5c833SDouglas Gilbert 	}
169038d5c833SDouglas Gilbert 	switch (reporting_opts) {
169138d5c833SDouglas Gilbert 	case 0:	/* all commands */
169238d5c833SDouglas Gilbert 		/* count number of commands */
169338d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
169438d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
169538d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
169638d5c833SDouglas Gilbert 				continue;
169738d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
169838d5c833SDouglas Gilbert 		}
169938d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
170038d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
170138d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
170238d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
170338d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
170438d5c833SDouglas Gilbert 				continue;
170538d5c833SDouglas Gilbert 			na = oip->num_attached;
170638d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
170738d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
170838d5c833SDouglas Gilbert 			if (rctd)
170938d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
171038d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
171138d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
171238d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
171338d5c833SDouglas Gilbert 			if (rctd)
171438d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
171538d5c833SDouglas Gilbert 			r_oip = oip;
171638d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
171738d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
171838d5c833SDouglas Gilbert 					continue;
171938d5c833SDouglas Gilbert 				offset += bump;
172038d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
172138d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
172238d5c833SDouglas Gilbert 				if (rctd)
172338d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
172438d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
172538d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
172638d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
172738d5c833SDouglas Gilbert 						   arr + offset + 6);
172838d5c833SDouglas Gilbert 				if (rctd)
172938d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
173038d5c833SDouglas Gilbert 							   arr + offset + 8);
173138d5c833SDouglas Gilbert 			}
173238d5c833SDouglas Gilbert 			oip = r_oip;
173338d5c833SDouglas Gilbert 			offset += bump;
173438d5c833SDouglas Gilbert 		}
173538d5c833SDouglas Gilbert 		break;
173638d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
173738d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
173838d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
173938d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
174038d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
174138d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
174238d5c833SDouglas Gilbert 			supp = 1;
174338d5c833SDouglas Gilbert 			offset = 4;
174438d5c833SDouglas Gilbert 		} else {
174538d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
174638d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
174738d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
174838d5c833SDouglas Gilbert 							     2, 2);
174938d5c833SDouglas Gilbert 					kfree(arr);
175038d5c833SDouglas Gilbert 					return check_condition_result;
175138d5c833SDouglas Gilbert 				}
175238d5c833SDouglas Gilbert 				req_sa = 0;
175338d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
175438d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
175538d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
175638d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
175738d5c833SDouglas Gilbert 				return check_condition_result;
175838d5c833SDouglas Gilbert 			}
175938d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
176038d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
176138d5c833SDouglas Gilbert 				supp = 3;
176238d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
176338d5c833SDouglas Gilbert 				na = oip->num_attached;
176438d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
176538d5c833SDouglas Gilbert 				     ++k, ++oip) {
176638d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
176738d5c833SDouglas Gilbert 						break;
176838d5c833SDouglas Gilbert 				}
176938d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
177038d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
177138d5c833SDouglas Gilbert 				na = oip->num_attached;
177238d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
177338d5c833SDouglas Gilbert 				     ++k, ++oip) {
177438d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
177538d5c833SDouglas Gilbert 						break;
177638d5c833SDouglas Gilbert 				}
177738d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
177838d5c833SDouglas Gilbert 			} else
177938d5c833SDouglas Gilbert 				supp = 3;
178038d5c833SDouglas Gilbert 			if (3 == supp) {
178138d5c833SDouglas Gilbert 				u = oip->len_mask[0];
178238d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
178338d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
178438d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
178538d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
178638d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
178738d5c833SDouglas Gilbert 				offset = 4 + u;
178838d5c833SDouglas Gilbert 			} else
178938d5c833SDouglas Gilbert 				offset = 4;
179038d5c833SDouglas Gilbert 		}
179138d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
179238d5c833SDouglas Gilbert 		if (rctd) {
179338d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
179438d5c833SDouglas Gilbert 			offset += 12;
179538d5c833SDouglas Gilbert 		}
179638d5c833SDouglas Gilbert 		break;
179738d5c833SDouglas Gilbert 	default:
179838d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
179938d5c833SDouglas Gilbert 		kfree(arr);
180038d5c833SDouglas Gilbert 		return check_condition_result;
180138d5c833SDouglas Gilbert 	}
180238d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
180338d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
180438d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
180538d5c833SDouglas Gilbert 	kfree(arr);
180638d5c833SDouglas Gilbert 	return errsts;
180738d5c833SDouglas Gilbert }
180838d5c833SDouglas Gilbert 
1809fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1810fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
181138d5c833SDouglas Gilbert {
181238d5c833SDouglas Gilbert 	bool repd;
181338d5c833SDouglas Gilbert 	u32 alloc_len, len;
181438d5c833SDouglas Gilbert 	u8 arr[16];
181538d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
181638d5c833SDouglas Gilbert 
181738d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
181838d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
181938d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
182038d5c833SDouglas Gilbert 	if (alloc_len < 4) {
182138d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
182238d5c833SDouglas Gilbert 		return check_condition_result;
182338d5c833SDouglas Gilbert 	}
182438d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
182538d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
182638d5c833SDouglas Gilbert 	if (repd) {
182738d5c833SDouglas Gilbert 		arr[3] = 0xc;
182838d5c833SDouglas Gilbert 		len = 16;
182938d5c833SDouglas Gilbert 	} else
183038d5c833SDouglas Gilbert 		len = 4;
183138d5c833SDouglas Gilbert 
183238d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
183338d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
183438d5c833SDouglas Gilbert }
183538d5c833SDouglas Gilbert 
18361da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
18371da177e4SLinus Torvalds 
18381da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
18391da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
18401da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
18411da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
18421da177e4SLinus Torvalds 
18431da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
18441da177e4SLinus Torvalds 	if (1 == pcontrol)
18451da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
18461da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
18471da177e4SLinus Torvalds }
18481da177e4SLinus Torvalds 
18491da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
18501da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
18511da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
18521da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
18531da177e4SLinus Torvalds 
18541da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
18551da177e4SLinus Torvalds 	if (1 == pcontrol)
18561da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
18571da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
18581da177e4SLinus Torvalds }
18591da177e4SLinus Torvalds 
18601da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target)
18611da177e4SLinus Torvalds {       /* Format device page for mode_sense */
18621da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
18631da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
18641da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
18651da177e4SLinus Torvalds 
18661da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
1867773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
1868773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
1869773642d9SDouglas Gilbert 	if (sdebug_removable)
18701da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
18711da177e4SLinus Torvalds 	if (1 == pcontrol)
18721da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
18731da177e4SLinus Torvalds 	return sizeof(format_pg);
18741da177e4SLinus Torvalds }
18751da177e4SLinus Torvalds 
1876fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1877fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1878fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
1879fd32119bSDouglas Gilbert 
18801da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
18811da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
1882cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1883cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1884cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
18851da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
18861da177e4SLinus Torvalds 
1887773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
1888cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
18891da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
18901da177e4SLinus Torvalds 	if (1 == pcontrol)
1891cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1892cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
1893cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
18941da177e4SLinus Torvalds 	return sizeof(caching_pg);
18951da177e4SLinus Torvalds }
18961da177e4SLinus Torvalds 
1897fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
1898fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
1899fd32119bSDouglas Gilbert 
19001da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
19011da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
1902c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1903c65b1445SDouglas Gilbert 				        0, 0, 0, 0};
1904c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
19051da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
19061da177e4SLinus Torvalds 
1907773642d9SDouglas Gilbert 	if (sdebug_dsense)
19081da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
1909c65b1445SDouglas Gilbert 	else
1910c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
1911c6a44287SMartin K. Petersen 
1912773642d9SDouglas Gilbert 	if (sdebug_ato)
1913c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1914c6a44287SMartin K. Petersen 
19151da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
19161da177e4SLinus Torvalds 	if (1 == pcontrol)
1917c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1918c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1919c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
19201da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
19211da177e4SLinus Torvalds }
19221da177e4SLinus Torvalds 
1923c65b1445SDouglas Gilbert 
19241da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
19251da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
1926c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
19271da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
1928c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1929c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
1930c65b1445SDouglas Gilbert 
19311da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
19321da177e4SLinus Torvalds 	if (1 == pcontrol)
1933c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1934c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1935c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
19361da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
19371da177e4SLinus Torvalds }
19381da177e4SLinus Torvalds 
1939c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1940c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
1941c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1942c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1943c65b1445SDouglas Gilbert 
1944c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1945c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1946c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1947c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
1948c65b1445SDouglas Gilbert }
1949c65b1445SDouglas Gilbert 
1950c65b1445SDouglas Gilbert 
1951c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1952c65b1445SDouglas Gilbert 			      int target_dev_id)
1953c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
1954c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1955c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1956773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1957773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1958c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
1959c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1960c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1961c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1962773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1963773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1964c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
1965c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1966c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1967c65b1445SDouglas Gilbert 		};
1968c65b1445SDouglas Gilbert 	int port_a, port_b;
1969c65b1445SDouglas Gilbert 
19701b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
19711b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
19721b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
19731b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
1974c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1975c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1976c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1977773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
1978773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
1979c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1980c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1981c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
1982c65b1445SDouglas Gilbert }
1983c65b1445SDouglas Gilbert 
1984c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1985c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
1986c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1987c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1988c65b1445SDouglas Gilbert 		};
1989c65b1445SDouglas Gilbert 
1990c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1991c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1992c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1993c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
1994c65b1445SDouglas Gilbert }
1995c65b1445SDouglas Gilbert 
19961da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
19971da177e4SLinus Torvalds 
1998fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
1999fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
20001da177e4SLinus Torvalds {
200123183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
20021da177e4SLinus Torvalds 	unsigned char dev_spec;
2003760f3b03SDouglas Gilbert 	int alloc_len, offset, len, target_dev_id;
2004c2248fc9SDouglas Gilbert 	int target = scp->device->id;
20051da177e4SLinus Torvalds 	unsigned char * ap;
20061da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
200701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2008760f3b03SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, bad_pcode;
20091da177e4SLinus Torvalds 
2010760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
20111da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
20121da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
20131da177e4SLinus Torvalds 	subpcode = cmd[3];
20141da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2015760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2016760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
2017760f3b03SDouglas Gilbert 	if (is_disk && !dbd)
201823183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
201923183910SDouglas Gilbert 	else
202023183910SDouglas Gilbert 		bd_len = 0;
2021773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
20221da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
20231da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2024cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
20251da177e4SLinus Torvalds 		return check_condition_result;
20261da177e4SLinus Torvalds 	}
2027c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2028c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2029b01f6f83SDouglas Gilbert 	/* for disks set DPOFUA bit and clear write protect (WP) bit */
2030760f3b03SDouglas Gilbert 	if (is_disk)
2031b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
203223183910SDouglas Gilbert 	else
203323183910SDouglas Gilbert 		dev_spec = 0x0;
20341da177e4SLinus Torvalds 	if (msense_6) {
20351da177e4SLinus Torvalds 		arr[2] = dev_spec;
203623183910SDouglas Gilbert 		arr[3] = bd_len;
20371da177e4SLinus Torvalds 		offset = 4;
20381da177e4SLinus Torvalds 	} else {
20391da177e4SLinus Torvalds 		arr[3] = dev_spec;
204023183910SDouglas Gilbert 		if (16 == bd_len)
204123183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
204223183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
20431da177e4SLinus Torvalds 		offset = 8;
20441da177e4SLinus Torvalds 	}
20451da177e4SLinus Torvalds 	ap = arr + offset;
204628898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
204728898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
204828898873SFUJITA Tomonori 
204923183910SDouglas Gilbert 	if (8 == bd_len) {
2050773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2051773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2052773642d9SDouglas Gilbert 		else
2053773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2054773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
205523183910SDouglas Gilbert 		offset += bd_len;
205623183910SDouglas Gilbert 		ap = arr + offset;
205723183910SDouglas Gilbert 	} else if (16 == bd_len) {
2058773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2059773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
206023183910SDouglas Gilbert 		offset += bd_len;
206123183910SDouglas Gilbert 		ap = arr + offset;
206223183910SDouglas Gilbert 	}
20631da177e4SLinus Torvalds 
2064c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2065c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
206622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
20671da177e4SLinus Torvalds 		return check_condition_result;
20681da177e4SLinus Torvalds 	}
2069760f3b03SDouglas Gilbert 	bad_pcode = false;
2070760f3b03SDouglas Gilbert 
20711da177e4SLinus Torvalds 	switch (pcode) {
20721da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
20731da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
20741da177e4SLinus Torvalds 		offset += len;
20751da177e4SLinus Torvalds 		break;
20761da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
20771da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
20781da177e4SLinus Torvalds 		offset += len;
20791da177e4SLinus Torvalds 		break;
20801da177e4SLinus Torvalds         case 0x3:       /* Format device page, direct access */
2081760f3b03SDouglas Gilbert 		if (is_disk) {
20821da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
20831da177e4SLinus Torvalds 			offset += len;
2084760f3b03SDouglas Gilbert 		} else
2085760f3b03SDouglas Gilbert 			bad_pcode = true;
20861da177e4SLinus Torvalds                 break;
20871da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2088760f3b03SDouglas Gilbert 		if (is_disk) {
20891da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
20901da177e4SLinus Torvalds 			offset += len;
2091760f3b03SDouglas Gilbert 		} else
2092760f3b03SDouglas Gilbert 			bad_pcode = true;
20931da177e4SLinus Torvalds 		break;
20941da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
20951da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
20961da177e4SLinus Torvalds 		offset += len;
20971da177e4SLinus Torvalds 		break;
2098c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2099c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
210022017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2101c65b1445SDouglas Gilbert 			return check_condition_result;
2102c65b1445SDouglas Gilbert 	        }
2103c65b1445SDouglas Gilbert 		len = 0;
2104c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2105c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2106c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2107c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2108c65b1445SDouglas Gilbert 						  target_dev_id);
2109c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2110c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2111c65b1445SDouglas Gilbert 		offset += len;
2112c65b1445SDouglas Gilbert 		break;
21131da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
21141da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
21151da177e4SLinus Torvalds 		offset += len;
21161da177e4SLinus Torvalds 		break;
21171da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2118c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
21191da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
21201da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2121760f3b03SDouglas Gilbert 			if (is_disk) {
2122760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2123760f3b03SDouglas Gilbert 						      target);
2124760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2125760f3b03SDouglas Gilbert 						       target);
2126760f3b03SDouglas Gilbert 			}
21271da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2128c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2129c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2130c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2131c65b1445SDouglas Gilbert 						  target, target_dev_id);
2132c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2133c65b1445SDouglas Gilbert 			}
21341da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2135760f3b03SDouglas Gilbert 			offset += len;
2136c65b1445SDouglas Gilbert 		} else {
213722017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2138c65b1445SDouglas Gilbert 			return check_condition_result;
2139c65b1445SDouglas Gilbert                 }
21401da177e4SLinus Torvalds 		break;
21411da177e4SLinus Torvalds 	default:
2142760f3b03SDouglas Gilbert 		bad_pcode = true;
2143760f3b03SDouglas Gilbert 		break;
2144760f3b03SDouglas Gilbert 	}
2145760f3b03SDouglas Gilbert 	if (bad_pcode) {
214622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
21471da177e4SLinus Torvalds 		return check_condition_result;
21481da177e4SLinus Torvalds 	}
21491da177e4SLinus Torvalds 	if (msense_6)
21501da177e4SLinus Torvalds 		arr[0] = offset - 1;
2151773642d9SDouglas Gilbert 	else
2152773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
21531da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
21541da177e4SLinus Torvalds }
21551da177e4SLinus Torvalds 
2156c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2157c65b1445SDouglas Gilbert 
2158fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2159fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2160c65b1445SDouglas Gilbert {
2161c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2162c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2163c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
216401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2165c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2166c65b1445SDouglas Gilbert 
2167c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2168c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2169c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2170773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2171c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
217222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2173c65b1445SDouglas Gilbert 		return check_condition_result;
2174c65b1445SDouglas Gilbert 	}
2175c65b1445SDouglas Gilbert         res = fetch_to_dev_buffer(scp, arr, param_len);
2176c65b1445SDouglas Gilbert         if (-1 == res)
2177773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2178773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2179cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2180cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2181cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2182773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2183773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
218423183910SDouglas Gilbert 	if (md_len > 2) {
218522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2186c65b1445SDouglas Gilbert 		return check_condition_result;
2187c65b1445SDouglas Gilbert 	}
2188c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2189c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2190c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2191c65b1445SDouglas Gilbert 	if (ps) {
219222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2193c65b1445SDouglas Gilbert 		return check_condition_result;
2194c65b1445SDouglas Gilbert 	}
2195c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2196773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2197c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2198c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2199cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2200c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2201c65b1445SDouglas Gilbert 		return check_condition_result;
2202c65b1445SDouglas Gilbert 	}
2203c65b1445SDouglas Gilbert 	switch (mpage) {
2204cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2205cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2206cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2207cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2208cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2209cbf67842SDouglas Gilbert 		}
2210cbf67842SDouglas Gilbert 		break;
2211c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2212c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2213c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2214c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
2215773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2216cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2217c65b1445SDouglas Gilbert 		}
2218c65b1445SDouglas Gilbert 		break;
2219c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2220c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2221c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2222c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2223cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2224c65b1445SDouglas Gilbert 		}
2225c65b1445SDouglas Gilbert 		break;
2226c65b1445SDouglas Gilbert 	default:
2227c65b1445SDouglas Gilbert 		break;
2228c65b1445SDouglas Gilbert 	}
222922017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2230c65b1445SDouglas Gilbert 	return check_condition_result;
2231cbf67842SDouglas Gilbert set_mode_changed_ua:
2232cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2233cbf67842SDouglas Gilbert 	return 0;
2234c65b1445SDouglas Gilbert }
2235c65b1445SDouglas Gilbert 
2236c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr)
2237c65b1445SDouglas Gilbert {
2238c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2239c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2240c65b1445SDouglas Gilbert 		};
2241c65b1445SDouglas Gilbert 
2242c65b1445SDouglas Gilbert         memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2243c65b1445SDouglas Gilbert         return sizeof(temp_l_pg);
2244c65b1445SDouglas Gilbert }
2245c65b1445SDouglas Gilbert 
2246c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr)
2247c65b1445SDouglas Gilbert {
2248c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2249c65b1445SDouglas Gilbert 		};
2250c65b1445SDouglas Gilbert 
2251c65b1445SDouglas Gilbert         memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2252c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2253c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2254c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2255c65b1445SDouglas Gilbert 	}
2256c65b1445SDouglas Gilbert         return sizeof(ie_l_pg);
2257c65b1445SDouglas Gilbert }
2258c65b1445SDouglas Gilbert 
2259c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2260c65b1445SDouglas Gilbert 
2261c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp,
2262c65b1445SDouglas Gilbert                           struct sdebug_dev_info * devip)
2263c65b1445SDouglas Gilbert {
2264ab17241cSBart Van Assche 	int ppc, sp, pcode, subpcode, alloc_len, len, n;
2265c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
226601123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2267c65b1445SDouglas Gilbert 
2268c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2269c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2270c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2271c65b1445SDouglas Gilbert 	if (ppc || sp) {
227222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2273c65b1445SDouglas Gilbert 		return check_condition_result;
2274c65b1445SDouglas Gilbert 	}
2275c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
227623183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2277773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2278c65b1445SDouglas Gilbert 	arr[0] = pcode;
227923183910SDouglas Gilbert 	if (0 == subpcode) {
2280c65b1445SDouglas Gilbert 		switch (pcode) {
2281c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2282c65b1445SDouglas Gilbert 			n = 4;
2283c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2284c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2285c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2286c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2287c65b1445SDouglas Gilbert 			break;
2288c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2289c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2290c65b1445SDouglas Gilbert 			break;
2291c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2292c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2293c65b1445SDouglas Gilbert 			break;
2294c65b1445SDouglas Gilbert 		default:
229522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2296c65b1445SDouglas Gilbert 			return check_condition_result;
2297c65b1445SDouglas Gilbert 		}
229823183910SDouglas Gilbert 	} else if (0xff == subpcode) {
229923183910SDouglas Gilbert 		arr[0] |= 0x40;
230023183910SDouglas Gilbert 		arr[1] = subpcode;
230123183910SDouglas Gilbert 		switch (pcode) {
230223183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
230323183910SDouglas Gilbert 			n = 4;
230423183910SDouglas Gilbert 			arr[n++] = 0x0;
230523183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
230623183910SDouglas Gilbert 			arr[n++] = 0x0;
230723183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
230823183910SDouglas Gilbert 			arr[n++] = 0xd;
230923183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
231023183910SDouglas Gilbert 			arr[n++] = 0x2f;
231123183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
231223183910SDouglas Gilbert 			arr[3] = n - 4;
231323183910SDouglas Gilbert 			break;
231423183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
231523183910SDouglas Gilbert 			n = 4;
231623183910SDouglas Gilbert 			arr[n++] = 0xd;
231723183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
231823183910SDouglas Gilbert 			arr[3] = n - 4;
231923183910SDouglas Gilbert 			break;
232023183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
232123183910SDouglas Gilbert 			n = 4;
232223183910SDouglas Gilbert 			arr[n++] = 0x2f;
232323183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
232423183910SDouglas Gilbert 			arr[3] = n - 4;
232523183910SDouglas Gilbert 			break;
232623183910SDouglas Gilbert 		default:
232722017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
232823183910SDouglas Gilbert 			return check_condition_result;
232923183910SDouglas Gilbert 		}
233023183910SDouglas Gilbert 	} else {
233122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
233223183910SDouglas Gilbert 		return check_condition_result;
233323183910SDouglas Gilbert 	}
2334773642d9SDouglas Gilbert 	len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
2335c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
2336c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
2337c65b1445SDouglas Gilbert }
2338c65b1445SDouglas Gilbert 
2339cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp,
234019789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
23411da177e4SLinus Torvalds {
2342c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
234322017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
23441da177e4SLinus Torvalds 		return check_condition_result;
23451da177e4SLinus Torvalds 	}
2346c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2347c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
234822017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2349cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2350c65b1445SDouglas Gilbert 		return check_condition_result;
2351c65b1445SDouglas Gilbert 	}
235219789100SFUJITA Tomonori 	return 0;
235319789100SFUJITA Tomonori }
235419789100SFUJITA Tomonori 
2355a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
2356fd32119bSDouglas Gilbert static int do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num,
2357fd32119bSDouglas Gilbert 			    bool do_write)
235819789100SFUJITA Tomonori {
235919789100SFUJITA Tomonori 	int ret;
2360c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2361a4517511SAkinobu Mita 	struct scsi_data_buffer *sdb;
2362a4517511SAkinobu Mita 	enum dma_data_direction dir;
236319789100SFUJITA Tomonori 
2364c2248fc9SDouglas Gilbert 	if (do_write) {
2365a4517511SAkinobu Mita 		sdb = scsi_out(scmd);
2366a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
2367a4517511SAkinobu Mita 	} else {
2368a4517511SAkinobu Mita 		sdb = scsi_in(scmd);
2369a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2370a4517511SAkinobu Mita 	}
2371a4517511SAkinobu Mita 
2372a4517511SAkinobu Mita 	if (!sdb->length)
2373a4517511SAkinobu Mita 		return 0;
2374a4517511SAkinobu Mita 	if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2375a4517511SAkinobu Mita 		return -1;
237619789100SFUJITA Tomonori 
237719789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
237819789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
237919789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
238019789100SFUJITA Tomonori 
2381386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2382773642d9SDouglas Gilbert 		   fake_storep + (block * sdebug_sector_size),
2383773642d9SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, 0, do_write);
2384773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2385a4517511SAkinobu Mita 		return ret;
2386a4517511SAkinobu Mita 
2387a4517511SAkinobu Mita 	if (rest) {
2388386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2389773642d9SDouglas Gilbert 			    fake_storep, rest * sdebug_sector_size,
2390773642d9SDouglas Gilbert 			    (num - rest) * sdebug_sector_size, do_write);
2391a4517511SAkinobu Mita 	}
239219789100SFUJITA Tomonori 
239319789100SFUJITA Tomonori 	return ret;
239419789100SFUJITA Tomonori }
239519789100SFUJITA Tomonori 
239638d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of
239738d5c833SDouglas Gilbert  * arr into fake_store(lba,num) and return true. If comparison fails then
239838d5c833SDouglas Gilbert  * return false. */
2399fd32119bSDouglas Gilbert static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
240038d5c833SDouglas Gilbert {
240138d5c833SDouglas Gilbert 	bool res;
240238d5c833SDouglas Gilbert 	u64 block, rest = 0;
240338d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2404773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
240538d5c833SDouglas Gilbert 
240638d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
240738d5c833SDouglas Gilbert 	if (block + num > store_blks)
240838d5c833SDouglas Gilbert 		rest = block + num - store_blks;
240938d5c833SDouglas Gilbert 
241038d5c833SDouglas Gilbert 	res = !memcmp(fake_storep + (block * lb_size), arr,
241138d5c833SDouglas Gilbert 		      (num - rest) * lb_size);
241238d5c833SDouglas Gilbert 	if (!res)
241338d5c833SDouglas Gilbert 		return res;
241438d5c833SDouglas Gilbert 	if (rest)
241538d5c833SDouglas Gilbert 		res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
241638d5c833SDouglas Gilbert 			     rest * lb_size);
241738d5c833SDouglas Gilbert 	if (!res)
241838d5c833SDouglas Gilbert 		return res;
241938d5c833SDouglas Gilbert 	arr += num * lb_size;
242038d5c833SDouglas Gilbert 	memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
242138d5c833SDouglas Gilbert 	if (rest)
242238d5c833SDouglas Gilbert 		memcpy(fake_storep, arr + ((num - rest) * lb_size),
242338d5c833SDouglas Gilbert 		       rest * lb_size);
242438d5c833SDouglas Gilbert 	return res;
242538d5c833SDouglas Gilbert }
242638d5c833SDouglas Gilbert 
242751d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2428beb40ea4SAkinobu Mita {
242951d648afSAkinobu Mita 	__be16 csum;
2430beb40ea4SAkinobu Mita 
2431773642d9SDouglas Gilbert 	if (sdebug_guard)
243251d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
243351d648afSAkinobu Mita 	else
2434beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
243551d648afSAkinobu Mita 
2436beb40ea4SAkinobu Mita 	return csum;
2437beb40ea4SAkinobu Mita }
2438beb40ea4SAkinobu Mita 
24396ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
2440beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
2441beb40ea4SAkinobu Mita {
2442773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
2443beb40ea4SAkinobu Mita 
2444beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
2445c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
2446beb40ea4SAkinobu Mita 			(unsigned long)sector,
2447beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
2448beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
2449beb40ea4SAkinobu Mita 		return 0x01;
2450beb40ea4SAkinobu Mita 	}
24518475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
2452beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
2453c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2454c1287970STomas Winkler 			(unsigned long)sector);
2455beb40ea4SAkinobu Mita 		return 0x03;
2456beb40ea4SAkinobu Mita 	}
24578475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2458beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
2459c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2460c1287970STomas Winkler 			(unsigned long)sector);
2461beb40ea4SAkinobu Mita 		return 0x03;
2462beb40ea4SAkinobu Mita 	}
2463beb40ea4SAkinobu Mita 	return 0;
2464beb40ea4SAkinobu Mita }
2465beb40ea4SAkinobu Mita 
2466bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
246765f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
2468c6a44287SMartin K. Petersen {
2469be4e11beSAkinobu Mita 	size_t resid;
2470c6a44287SMartin K. Petersen 	void *paddr;
247114faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
2472be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
2473c6a44287SMartin K. Petersen 
2474e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
2475e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
2476c6a44287SMartin K. Petersen 
2477be4e11beSAkinobu Mita 	sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2478be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2479be4e11beSAkinobu Mita 			(read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2480be4e11beSAkinobu Mita 
2481be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
2482be4e11beSAkinobu Mita 		size_t len = min(miter.length, resid);
248314faa944SAkinobu Mita 		void *start = dif_store(sector);
2484be4e11beSAkinobu Mita 		size_t rest = 0;
248514faa944SAkinobu Mita 
248614faa944SAkinobu Mita 		if (dif_store_end < start + len)
248714faa944SAkinobu Mita 			rest = start + len - dif_store_end;
2488c6a44287SMartin K. Petersen 
2489be4e11beSAkinobu Mita 		paddr = miter.addr;
249014faa944SAkinobu Mita 
249165f72f2aSAkinobu Mita 		if (read)
249265f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
249365f72f2aSAkinobu Mita 		else
249465f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
249565f72f2aSAkinobu Mita 
249665f72f2aSAkinobu Mita 		if (rest) {
249765f72f2aSAkinobu Mita 			if (read)
249814faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
249965f72f2aSAkinobu Mita 			else
250065f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
250165f72f2aSAkinobu Mita 		}
2502c6a44287SMartin K. Petersen 
2503e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
2504c6a44287SMartin K. Petersen 		resid -= len;
2505c6a44287SMartin K. Petersen 	}
2506be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
2507bb8c063cSAkinobu Mita }
2508c6a44287SMartin K. Petersen 
2509bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2510bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
2511bb8c063cSAkinobu Mita {
2512bb8c063cSAkinobu Mita 	unsigned int i;
25136ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
2514bb8c063cSAkinobu Mita 	sector_t sector;
2515bb8c063cSAkinobu Mita 
2516c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
2517bb8c063cSAkinobu Mita 		int ret;
2518bb8c063cSAkinobu Mita 
2519bb8c063cSAkinobu Mita 		sector = start_sec + i;
2520bb8c063cSAkinobu Mita 		sdt = dif_store(sector);
2521bb8c063cSAkinobu Mita 
252251d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
2523bb8c063cSAkinobu Mita 			continue;
2524bb8c063cSAkinobu Mita 
2525bb8c063cSAkinobu Mita 		ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2526bb8c063cSAkinobu Mita 		if (ret) {
2527bb8c063cSAkinobu Mita 			dif_errors++;
2528bb8c063cSAkinobu Mita 			return ret;
2529bb8c063cSAkinobu Mita 		}
2530bb8c063cSAkinobu Mita 	}
2531bb8c063cSAkinobu Mita 
253265f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, true);
2533c6a44287SMartin K. Petersen 	dix_reads++;
2534c6a44287SMartin K. Petersen 
2535c6a44287SMartin K. Petersen 	return 0;
2536c6a44287SMartin K. Petersen }
2537c6a44287SMartin K. Petersen 
2538fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
253919789100SFUJITA Tomonori {
2540c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2541c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
2542c2248fc9SDouglas Gilbert 	u64 lba;
2543c2248fc9SDouglas Gilbert 	u32 num;
2544c2248fc9SDouglas Gilbert 	u32 ei_lba;
254519789100SFUJITA Tomonori 	unsigned long iflags;
254619789100SFUJITA Tomonori 	int ret;
2547c2248fc9SDouglas Gilbert 	bool check_prot;
254819789100SFUJITA Tomonori 
2549c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2550c2248fc9SDouglas Gilbert 	case READ_16:
2551c2248fc9SDouglas Gilbert 		ei_lba = 0;
2552c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2553c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2554c2248fc9SDouglas Gilbert 		check_prot = true;
2555c2248fc9SDouglas Gilbert 		break;
2556c2248fc9SDouglas Gilbert 	case READ_10:
2557c2248fc9SDouglas Gilbert 		ei_lba = 0;
2558c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2559c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2560c2248fc9SDouglas Gilbert 		check_prot = true;
2561c2248fc9SDouglas Gilbert 		break;
2562c2248fc9SDouglas Gilbert 	case READ_6:
2563c2248fc9SDouglas Gilbert 		ei_lba = 0;
2564c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2565c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2566c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2567c2248fc9SDouglas Gilbert 		check_prot = true;
2568c2248fc9SDouglas Gilbert 		break;
2569c2248fc9SDouglas Gilbert 	case READ_12:
2570c2248fc9SDouglas Gilbert 		ei_lba = 0;
2571c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2572c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2573c2248fc9SDouglas Gilbert 		check_prot = true;
2574c2248fc9SDouglas Gilbert 		break;
2575c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
2576c2248fc9SDouglas Gilbert 		ei_lba = 0;
2577c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2578c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2579c2248fc9SDouglas Gilbert 		check_prot = false;
2580c2248fc9SDouglas Gilbert 		break;
2581c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
2582c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2583c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2584c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2585c2248fc9SDouglas Gilbert 		check_prot = false;
2586c2248fc9SDouglas Gilbert 		break;
2587c2248fc9SDouglas Gilbert 	}
2588f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
25898475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2590c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2591c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2592c2248fc9SDouglas Gilbert 			return check_condition_result;
2593c2248fc9SDouglas Gilbert 		}
25948475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
25958475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
2596c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2597c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2598c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2599c2248fc9SDouglas Gilbert 	}
2600f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
2601c4837394SDouglas Gilbert 		sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
2602c2248fc9SDouglas Gilbert 
2603c4837394SDouglas Gilbert 		if (sqcp) {
2604c4837394SDouglas Gilbert 			if (sqcp->inj_short)
2605c2248fc9SDouglas Gilbert 				num /= 2;
2606c2248fc9SDouglas Gilbert 		}
2607c4837394SDouglas Gilbert 	} else
2608c4837394SDouglas Gilbert 		sqcp = NULL;
2609c2248fc9SDouglas Gilbert 
2610c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2611f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
2612c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2613c2248fc9SDouglas Gilbert 		return check_condition_result;
2614c2248fc9SDouglas Gilbert 	}
2615c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2616f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
2617c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2618c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2619c2248fc9SDouglas Gilbert 		return check_condition_result;
2620c2248fc9SDouglas Gilbert 	}
262119789100SFUJITA Tomonori 
2622f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
262332f7ef73SDouglas Gilbert 		     (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
2624f46eb0e9SDouglas Gilbert 		     ((lba + num) > OPT_MEDIUM_ERR_ADDR))) {
2625c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
2626c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
2627c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
2628c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2629c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
263032f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
263132f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
2632c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
2633c65b1445SDouglas Gilbert 		}
2634c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
26351da177e4SLinus Torvalds 		return check_condition_result;
26361da177e4SLinus Torvalds 	}
2637c6a44287SMartin K. Petersen 
26386c78cc06SAkinobu Mita 	read_lock_irqsave(&atomic_rw, iflags);
26396c78cc06SAkinobu Mita 
2640c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2641f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
2642c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
2643c6a44287SMartin K. Petersen 
2644c6a44287SMartin K. Petersen 		if (prot_ret) {
26456c78cc06SAkinobu Mita 			read_unlock_irqrestore(&atomic_rw, iflags);
2646c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
2647c6a44287SMartin K. Petersen 			return illegal_condition_result;
2648c6a44287SMartin K. Petersen 		}
2649c6a44287SMartin K. Petersen 	}
2650c6a44287SMartin K. Petersen 
2651c2248fc9SDouglas Gilbert 	ret = do_device_access(scp, lba, num, false);
26521da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
2653f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
2654a4517511SAkinobu Mita 		return DID_ERROR << 16;
2655a4517511SAkinobu Mita 
2656c2248fc9SDouglas Gilbert 	scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
2657a4517511SAkinobu Mita 
2658c4837394SDouglas Gilbert 	if (unlikely(sqcp)) {
2659c4837394SDouglas Gilbert 		if (sqcp->inj_recovered) {
2660c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
2661c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
2662c2248fc9SDouglas Gilbert 			return check_condition_result;
2663c4837394SDouglas Gilbert 		} else if (sqcp->inj_transport) {
2664c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND,
2665c2248fc9SDouglas Gilbert 					TRANSPORT_PROBLEM, ACK_NAK_TO);
2666c2248fc9SDouglas Gilbert 			return check_condition_result;
2667c4837394SDouglas Gilbert 		} else if (sqcp->inj_dif) {
2668c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
2669c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2670c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2671c4837394SDouglas Gilbert 		} else if (sqcp->inj_dix) {
2672c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2673c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2674c2248fc9SDouglas Gilbert 		}
2675c2248fc9SDouglas Gilbert 	}
2676a4517511SAkinobu Mita 	return 0;
26771da177e4SLinus Torvalds }
26781da177e4SLinus Torvalds 
267958a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len)
2680c6a44287SMartin K. Petersen {
2681cbf67842SDouglas Gilbert 	int i, j, n;
2682c6a44287SMartin K. Petersen 
2683cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
2684c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
2685cbf67842SDouglas Gilbert 		char b[128];
2686c6a44287SMartin K. Petersen 
2687cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
2688c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
2689c6a44287SMartin K. Petersen 
2690cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
2691cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2692cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
2693cbf67842SDouglas Gilbert 			else
2694cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2695cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
2696cbf67842SDouglas Gilbert 		}
2697cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
2698c6a44287SMartin K. Petersen 	}
2699c6a44287SMartin K. Petersen }
2700c6a44287SMartin K. Petersen 
2701c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
2702395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
2703c6a44287SMartin K. Petersen {
2704be4e11beSAkinobu Mita 	int ret;
27056ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
2706be4e11beSAkinobu Mita 	void *daddr;
270765f72f2aSAkinobu Mita 	sector_t sector = start_sec;
2708c6a44287SMartin K. Petersen 	int ppage_offset;
2709be4e11beSAkinobu Mita 	int dpage_offset;
2710be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
2711be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
2712c6a44287SMartin K. Petersen 
2713c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
2714c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2715c6a44287SMartin K. Petersen 
2716be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2717be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
2718be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2719be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2720be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2721c6a44287SMartin K. Petersen 
2722be4e11beSAkinobu Mita 	/* For each protection page */
2723be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
2724be4e11beSAkinobu Mita 		dpage_offset = 0;
2725be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
2726be4e11beSAkinobu Mita 			ret = 0x01;
2727be4e11beSAkinobu Mita 			goto out;
2728c6a44287SMartin K. Petersen 		}
2729c6a44287SMartin K. Petersen 
2730be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
27316ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
2732be4e11beSAkinobu Mita 			/* If we're at the end of the current
2733be4e11beSAkinobu Mita 			 * data page advance to the next one
2734be4e11beSAkinobu Mita 			 */
2735be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
2736be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
2737be4e11beSAkinobu Mita 					ret = 0x01;
2738be4e11beSAkinobu Mita 					goto out;
2739be4e11beSAkinobu Mita 				}
2740be4e11beSAkinobu Mita 				dpage_offset = 0;
2741be4e11beSAkinobu Mita 			}
2742c6a44287SMartin K. Petersen 
2743be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
2744be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
2745be4e11beSAkinobu Mita 
2746be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
2747beb40ea4SAkinobu Mita 			if (ret) {
2748773642d9SDouglas Gilbert 				dump_sector(daddr, sdebug_sector_size);
2749395cef03SMartin K. Petersen 				goto out;
2750395cef03SMartin K. Petersen 			}
2751395cef03SMartin K. Petersen 
2752c6a44287SMartin K. Petersen 			sector++;
2753395cef03SMartin K. Petersen 			ei_lba++;
2754773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
2755c6a44287SMartin K. Petersen 		}
2756be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
2757be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
2758c6a44287SMartin K. Petersen 	}
2759be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2760c6a44287SMartin K. Petersen 
276165f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
2762c6a44287SMartin K. Petersen 	dix_writes++;
2763c6a44287SMartin K. Petersen 
2764c6a44287SMartin K. Petersen 	return 0;
2765c6a44287SMartin K. Petersen 
2766c6a44287SMartin K. Petersen out:
2767c6a44287SMartin K. Petersen 	dif_errors++;
2768be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
2769be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2770c6a44287SMartin K. Petersen 	return ret;
2771c6a44287SMartin K. Petersen }
2772c6a44287SMartin K. Petersen 
2773b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
2774b90ebc3dSAkinobu Mita {
2775773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2776773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2777773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
2778b90ebc3dSAkinobu Mita 	return lba;
2779b90ebc3dSAkinobu Mita }
2780b90ebc3dSAkinobu Mita 
2781b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
2782b90ebc3dSAkinobu Mita {
2783773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
2784a027b5b9SAkinobu Mita 
2785773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2786773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
2787a027b5b9SAkinobu Mita 	return lba;
2788a027b5b9SAkinobu Mita }
2789a027b5b9SAkinobu Mita 
279044d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
279144d92694SMartin K. Petersen {
2792b90ebc3dSAkinobu Mita 	sector_t end;
2793b90ebc3dSAkinobu Mita 	unsigned int mapped;
2794b90ebc3dSAkinobu Mita 	unsigned long index;
2795b90ebc3dSAkinobu Mita 	unsigned long next;
279644d92694SMartin K. Petersen 
2797b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
2798b90ebc3dSAkinobu Mita 	mapped = test_bit(index, map_storep);
279944d92694SMartin K. Petersen 
280044d92694SMartin K. Petersen 	if (mapped)
2801b90ebc3dSAkinobu Mita 		next = find_next_zero_bit(map_storep, map_size, index);
280244d92694SMartin K. Petersen 	else
2803b90ebc3dSAkinobu Mita 		next = find_next_bit(map_storep, map_size, index);
280444d92694SMartin K. Petersen 
2805b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
280644d92694SMartin K. Petersen 	*num = end - lba;
280744d92694SMartin K. Petersen 	return mapped;
280844d92694SMartin K. Petersen }
280944d92694SMartin K. Petersen 
281044d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
281144d92694SMartin K. Petersen {
281244d92694SMartin K. Petersen 	sector_t end = lba + len;
281344d92694SMartin K. Petersen 
281444d92694SMartin K. Petersen 	while (lba < end) {
2815b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
281644d92694SMartin K. Petersen 
2817b90ebc3dSAkinobu Mita 		if (index < map_size)
2818b90ebc3dSAkinobu Mita 			set_bit(index, map_storep);
281944d92694SMartin K. Petersen 
2820b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
282144d92694SMartin K. Petersen 	}
282244d92694SMartin K. Petersen }
282344d92694SMartin K. Petersen 
282444d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
282544d92694SMartin K. Petersen {
282644d92694SMartin K. Petersen 	sector_t end = lba + len;
282744d92694SMartin K. Petersen 
282844d92694SMartin K. Petersen 	while (lba < end) {
2829b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
283044d92694SMartin K. Petersen 
2831b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
2832773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
2833b90ebc3dSAkinobu Mita 		    index < map_size) {
2834b90ebc3dSAkinobu Mita 			clear_bit(index, map_storep);
2835760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
2836be1dd78dSEric Sandeen 				memset(fake_storep +
2837760f3b03SDouglas Gilbert 				       lba * sdebug_sector_size,
2838760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
2839773642d9SDouglas Gilbert 				       sdebug_sector_size *
2840773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2841be1dd78dSEric Sandeen 			}
2842e9926b43SAkinobu Mita 			if (dif_storep) {
2843e9926b43SAkinobu Mita 				memset(dif_storep + lba, 0xff,
2844e9926b43SAkinobu Mita 				       sizeof(*dif_storep) *
2845773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2846e9926b43SAkinobu Mita 			}
2847b90ebc3dSAkinobu Mita 		}
2848b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
284944d92694SMartin K. Petersen 	}
285044d92694SMartin K. Petersen }
285144d92694SMartin K. Petersen 
2852fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
28531da177e4SLinus Torvalds {
2854c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2855c2248fc9SDouglas Gilbert 	u64 lba;
2856c2248fc9SDouglas Gilbert 	u32 num;
2857c2248fc9SDouglas Gilbert 	u32 ei_lba;
28581da177e4SLinus Torvalds 	unsigned long iflags;
285919789100SFUJITA Tomonori 	int ret;
2860c2248fc9SDouglas Gilbert 	bool check_prot;
28611da177e4SLinus Torvalds 
2862c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2863c2248fc9SDouglas Gilbert 	case WRITE_16:
2864c2248fc9SDouglas Gilbert 		ei_lba = 0;
2865c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2866c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2867c2248fc9SDouglas Gilbert 		check_prot = true;
2868c2248fc9SDouglas Gilbert 		break;
2869c2248fc9SDouglas Gilbert 	case WRITE_10:
2870c2248fc9SDouglas Gilbert 		ei_lba = 0;
2871c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2872c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2873c2248fc9SDouglas Gilbert 		check_prot = true;
2874c2248fc9SDouglas Gilbert 		break;
2875c2248fc9SDouglas Gilbert 	case WRITE_6:
2876c2248fc9SDouglas Gilbert 		ei_lba = 0;
2877c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2878c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2879c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2880c2248fc9SDouglas Gilbert 		check_prot = true;
2881c2248fc9SDouglas Gilbert 		break;
2882c2248fc9SDouglas Gilbert 	case WRITE_12:
2883c2248fc9SDouglas Gilbert 		ei_lba = 0;
2884c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2885c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2886c2248fc9SDouglas Gilbert 		check_prot = true;
2887c2248fc9SDouglas Gilbert 		break;
2888c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
2889c2248fc9SDouglas Gilbert 		ei_lba = 0;
2890c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2891c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2892c2248fc9SDouglas Gilbert 		check_prot = false;
2893c2248fc9SDouglas Gilbert 		break;
2894c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
2895c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2896c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2897c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2898c2248fc9SDouglas Gilbert 		check_prot = false;
2899c2248fc9SDouglas Gilbert 		break;
2900c2248fc9SDouglas Gilbert 	}
2901f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
29028475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2903c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2904c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2905c2248fc9SDouglas Gilbert 			return check_condition_result;
2906c2248fc9SDouglas Gilbert 		}
29078475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
29088475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
2909c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2910c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2911c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2912c2248fc9SDouglas Gilbert 	}
2913c2248fc9SDouglas Gilbert 
2914c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2915f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
2916c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2917c2248fc9SDouglas Gilbert 		return check_condition_result;
2918c2248fc9SDouglas Gilbert 	}
2919c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2920f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
2921c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2922c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2923c2248fc9SDouglas Gilbert 		return check_condition_result;
2924c2248fc9SDouglas Gilbert 	}
29251da177e4SLinus Torvalds 
29266c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
29276c78cc06SAkinobu Mita 
2928c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2929f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
2930c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
2931c6a44287SMartin K. Petersen 
2932c6a44287SMartin K. Petersen 		if (prot_ret) {
29336c78cc06SAkinobu Mita 			write_unlock_irqrestore(&atomic_rw, iflags);
2934c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
2935c6a44287SMartin K. Petersen 			return illegal_condition_result;
2936c6a44287SMartin K. Petersen 		}
2937c6a44287SMartin K. Petersen 	}
2938c6a44287SMartin K. Petersen 
2939c2248fc9SDouglas Gilbert 	ret = do_device_access(scp, lba, num, true);
2940f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
294144d92694SMartin K. Petersen 		map_region(lba, num);
29421da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
2943f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
2944773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2945c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
2946c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
2947c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2948cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
2949773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
295044d92694SMartin K. Petersen 
2951f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
2952c4837394SDouglas Gilbert 		struct sdebug_queued_cmd *sqcp =
2953c4837394SDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
2954c2248fc9SDouglas Gilbert 
2955c4837394SDouglas Gilbert 		if (sqcp) {
2956c4837394SDouglas Gilbert 			if (sqcp->inj_recovered) {
2957c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR,
2958c2248fc9SDouglas Gilbert 						THRESHOLD_EXCEEDED, 0);
2959c2248fc9SDouglas Gilbert 				return check_condition_result;
2960c4837394SDouglas Gilbert 			} else if (sqcp->inj_dif) {
2961c2248fc9SDouglas Gilbert 				/* Logical block guard check failed */
2962c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2963c2248fc9SDouglas Gilbert 				return illegal_condition_result;
2964c4837394SDouglas Gilbert 			} else if (sqcp->inj_dix) {
2965c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2966c2248fc9SDouglas Gilbert 				return illegal_condition_result;
2967c2248fc9SDouglas Gilbert 			}
2968c2248fc9SDouglas Gilbert 		}
2969c4837394SDouglas Gilbert 	}
29701da177e4SLinus Torvalds 	return 0;
29711da177e4SLinus Torvalds }
29721da177e4SLinus Torvalds 
2973fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
2974fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
297544d92694SMartin K. Petersen {
297644d92694SMartin K. Petersen 	unsigned long iflags;
297744d92694SMartin K. Petersen 	unsigned long long i;
297844d92694SMartin K. Petersen 	int ret;
2979773642d9SDouglas Gilbert 	u64 lba_off;
298044d92694SMartin K. Petersen 
2981c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num);
298244d92694SMartin K. Petersen 	if (ret)
298344d92694SMartin K. Petersen 		return ret;
298444d92694SMartin K. Petersen 
298544d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
298644d92694SMartin K. Petersen 
29879ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
298844d92694SMartin K. Petersen 		unmap_region(lba, num);
298944d92694SMartin K. Petersen 		goto out;
299044d92694SMartin K. Petersen 	}
299144d92694SMartin K. Petersen 
2992773642d9SDouglas Gilbert 	lba_off = lba * sdebug_sector_size;
2993c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
2994c2248fc9SDouglas Gilbert 	if (ndob) {
2995773642d9SDouglas Gilbert 		memset(fake_storep + lba_off, 0, sdebug_sector_size);
2996c2248fc9SDouglas Gilbert 		ret = 0;
2997c2248fc9SDouglas Gilbert 	} else
2998773642d9SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
2999773642d9SDouglas Gilbert 					  sdebug_sector_size);
300044d92694SMartin K. Petersen 
300144d92694SMartin K. Petersen 	if (-1 == ret) {
300244d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
3003773642d9SDouglas Gilbert 		return DID_ERROR << 16;
3004773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
3005c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3006cbf67842SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
3007cbf67842SDouglas Gilbert 			    my_name, "write same",
3008773642d9SDouglas Gilbert 			    num * sdebug_sector_size, ret);
300944d92694SMartin K. Petersen 
301044d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
301144d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
3012773642d9SDouglas Gilbert 		memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
3013773642d9SDouglas Gilbert 		       fake_storep + lba_off,
3014773642d9SDouglas Gilbert 		       sdebug_sector_size);
301544d92694SMartin K. Petersen 
30169ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
301744d92694SMartin K. Petersen 		map_region(lba, num);
301844d92694SMartin K. Petersen out:
301944d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
302044d92694SMartin K. Petersen 
302144d92694SMartin K. Petersen 	return 0;
302244d92694SMartin K. Petersen }
302344d92694SMartin K. Petersen 
3024fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3025fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3026c2248fc9SDouglas Gilbert {
3027c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3028c2248fc9SDouglas Gilbert 	u32 lba;
3029c2248fc9SDouglas Gilbert 	u16 num;
3030c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3031c2248fc9SDouglas Gilbert 	bool unmap = false;
3032c2248fc9SDouglas Gilbert 
3033c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3034773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3035c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3036c2248fc9SDouglas Gilbert 			return check_condition_result;
3037c2248fc9SDouglas Gilbert 		} else
3038c2248fc9SDouglas Gilbert 			unmap = true;
3039c2248fc9SDouglas Gilbert 	}
3040c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3041c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3042773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3043c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3044c2248fc9SDouglas Gilbert 		return check_condition_result;
3045c2248fc9SDouglas Gilbert 	}
3046c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3047c2248fc9SDouglas Gilbert }
3048c2248fc9SDouglas Gilbert 
3049fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3050fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3051c2248fc9SDouglas Gilbert {
3052c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3053c2248fc9SDouglas Gilbert 	u64 lba;
3054c2248fc9SDouglas Gilbert 	u32 num;
3055c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3056c2248fc9SDouglas Gilbert 	bool unmap = false;
3057c2248fc9SDouglas Gilbert 	bool ndob = false;
3058c2248fc9SDouglas Gilbert 
3059c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3060773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3061c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3062c2248fc9SDouglas Gilbert 			return check_condition_result;
3063c2248fc9SDouglas Gilbert 		} else
3064c2248fc9SDouglas Gilbert 			unmap = true;
3065c2248fc9SDouglas Gilbert 	}
3066c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3067c2248fc9SDouglas Gilbert 		ndob = true;
3068c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3069c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3070773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3071c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3072c2248fc9SDouglas Gilbert 		return check_condition_result;
3073c2248fc9SDouglas Gilbert 	}
3074c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3075c2248fc9SDouglas Gilbert }
3076c2248fc9SDouglas Gilbert 
3077acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3078acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3079acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3080fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3081fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3082acafd0b9SEwan D. Milne {
3083acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3084acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3085acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3086acafd0b9SEwan D. Milne 	u8 mode;
3087acafd0b9SEwan D. Milne 
3088acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3089acafd0b9SEwan D. Milne 	switch (mode) {
3090acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3091acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3092acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3093acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3094acafd0b9SEwan D. Milne 		break;
3095acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3096acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3097acafd0b9SEwan D. Milne 		break;
3098acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3099acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3100acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3101acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3102acafd0b9SEwan D. Milne 				    dev_list)
3103acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3104acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3105acafd0b9SEwan D. Milne 				if (devip != dp)
3106acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3107acafd0b9SEwan D. Milne 						dp->uas_bm);
3108acafd0b9SEwan D. Milne 			}
3109acafd0b9SEwan D. Milne 		break;
3110acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3111acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3112acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3113acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3114acafd0b9SEwan D. Milne 				    dev_list)
3115acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3116acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3117acafd0b9SEwan D. Milne 					dp->uas_bm);
3118acafd0b9SEwan D. Milne 		break;
3119acafd0b9SEwan D. Milne 	default:
3120acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3121acafd0b9SEwan D. Milne 		break;
3122acafd0b9SEwan D. Milne 	}
3123acafd0b9SEwan D. Milne 	return 0;
3124acafd0b9SEwan D. Milne }
3125acafd0b9SEwan D. Milne 
3126fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3127fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
312838d5c833SDouglas Gilbert {
312938d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
313038d5c833SDouglas Gilbert 	u8 *arr;
313138d5c833SDouglas Gilbert 	u8 *fake_storep_hold;
313238d5c833SDouglas Gilbert 	u64 lba;
313338d5c833SDouglas Gilbert 	u32 dnum;
3134773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
313538d5c833SDouglas Gilbert 	u8 num;
313638d5c833SDouglas Gilbert 	unsigned long iflags;
313738d5c833SDouglas Gilbert 	int ret;
3138d467d31fSDouglas Gilbert 	int retval = 0;
313938d5c833SDouglas Gilbert 
3140d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
314138d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
314238d5c833SDouglas Gilbert 	if (0 == num)
314338d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
31448475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
314538d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
314638d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
314738d5c833SDouglas Gilbert 		return check_condition_result;
314838d5c833SDouglas Gilbert 	}
31498475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
31508475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
315138d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
315238d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
315338d5c833SDouglas Gilbert 			    "to DIF device\n");
315438d5c833SDouglas Gilbert 
315538d5c833SDouglas Gilbert 	/* inline check_device_access_params() */
315638d5c833SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
315738d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
315838d5c833SDouglas Gilbert 		return check_condition_result;
315938d5c833SDouglas Gilbert 	}
316038d5c833SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
316138d5c833SDouglas Gilbert 	if (num > sdebug_store_sectors) {
316238d5c833SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
316338d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
316438d5c833SDouglas Gilbert 		return check_condition_result;
316538d5c833SDouglas Gilbert 	}
3166d467d31fSDouglas Gilbert 	dnum = 2 * num;
3167d467d31fSDouglas Gilbert 	arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3168d467d31fSDouglas Gilbert 	if (NULL == arr) {
3169d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3170d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3171d467d31fSDouglas Gilbert 		return check_condition_result;
3172d467d31fSDouglas Gilbert 	}
317338d5c833SDouglas Gilbert 
317438d5c833SDouglas Gilbert 	write_lock_irqsave(&atomic_rw, iflags);
317538d5c833SDouglas Gilbert 
317638d5c833SDouglas Gilbert 	/* trick do_device_access() to fetch both compare and write buffers
317738d5c833SDouglas Gilbert 	 * from data-in into arr. Safe (atomic) since write_lock held. */
317838d5c833SDouglas Gilbert 	fake_storep_hold = fake_storep;
317938d5c833SDouglas Gilbert 	fake_storep = arr;
318038d5c833SDouglas Gilbert 	ret = do_device_access(scp, 0, dnum, true);
318138d5c833SDouglas Gilbert 	fake_storep = fake_storep_hold;
318238d5c833SDouglas Gilbert 	if (ret == -1) {
3183d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3184d467d31fSDouglas Gilbert 		goto cleanup;
3185773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
318638d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
318738d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
318838d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
318938d5c833SDouglas Gilbert 	if (!comp_write_worker(lba, num, arr)) {
319038d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3191d467d31fSDouglas Gilbert 		retval = check_condition_result;
3192d467d31fSDouglas Gilbert 		goto cleanup;
319338d5c833SDouglas Gilbert 	}
319438d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
319538d5c833SDouglas Gilbert 		map_region(lba, num);
3196d467d31fSDouglas Gilbert cleanup:
319738d5c833SDouglas Gilbert 	write_unlock_irqrestore(&atomic_rw, iflags);
3198d467d31fSDouglas Gilbert 	kfree(arr);
3199d467d31fSDouglas Gilbert 	return retval;
320038d5c833SDouglas Gilbert }
320138d5c833SDouglas Gilbert 
320244d92694SMartin K. Petersen struct unmap_block_desc {
320344d92694SMartin K. Petersen 	__be64	lba;
320444d92694SMartin K. Petersen 	__be32	blocks;
320544d92694SMartin K. Petersen 	__be32	__reserved;
320644d92694SMartin K. Petersen };
320744d92694SMartin K. Petersen 
3208fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
320944d92694SMartin K. Petersen {
321044d92694SMartin K. Petersen 	unsigned char *buf;
321144d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
321244d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
321344d92694SMartin K. Petersen 	int ret;
32146c78cc06SAkinobu Mita 	unsigned long iflags;
321544d92694SMartin K. Petersen 
321644d92694SMartin K. Petersen 
3217c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3218c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3219c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3220c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
322144d92694SMartin K. Petersen 
322244d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3223773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3224c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
322544d92694SMartin K. Petersen 		return check_condition_result;
3226c2248fc9SDouglas Gilbert 	}
322744d92694SMartin K. Petersen 
3228b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3229c2248fc9SDouglas Gilbert 	if (!buf) {
3230c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3231c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3232c2248fc9SDouglas Gilbert 		return check_condition_result;
3233c2248fc9SDouglas Gilbert 	}
3234c2248fc9SDouglas Gilbert 
3235c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
323644d92694SMartin K. Petersen 
323744d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
323844d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
323944d92694SMartin K. Petersen 
324044d92694SMartin K. Petersen 	desc = (void *)&buf[8];
324144d92694SMartin K. Petersen 
32426c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
32436c78cc06SAkinobu Mita 
324444d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
324544d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
324644d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
324744d92694SMartin K. Petersen 
3248c2248fc9SDouglas Gilbert 		ret = check_device_access_params(scp, lba, num);
324944d92694SMartin K. Petersen 		if (ret)
325044d92694SMartin K. Petersen 			goto out;
325144d92694SMartin K. Petersen 
325244d92694SMartin K. Petersen 		unmap_region(lba, num);
325344d92694SMartin K. Petersen 	}
325444d92694SMartin K. Petersen 
325544d92694SMartin K. Petersen 	ret = 0;
325644d92694SMartin K. Petersen 
325744d92694SMartin K. Petersen out:
32586c78cc06SAkinobu Mita 	write_unlock_irqrestore(&atomic_rw, iflags);
325944d92694SMartin K. Petersen 	kfree(buf);
326044d92694SMartin K. Petersen 
326144d92694SMartin K. Petersen 	return ret;
326244d92694SMartin K. Petersen }
326344d92694SMartin K. Petersen 
326444d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
326544d92694SMartin K. Petersen 
3266fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
3267fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
326844d92694SMartin K. Petersen {
3269c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3270c2248fc9SDouglas Gilbert 	u64 lba;
3271c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
3272c2248fc9SDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
327344d92694SMartin K. Petersen 	int ret;
327444d92694SMartin K. Petersen 
3275c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3276c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
327744d92694SMartin K. Petersen 
327844d92694SMartin K. Petersen 	if (alloc_len < 24)
327944d92694SMartin K. Petersen 		return 0;
328044d92694SMartin K. Petersen 
3281c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, 1);
328244d92694SMartin K. Petersen 	if (ret)
328344d92694SMartin K. Petersen 		return ret;
328444d92694SMartin K. Petersen 
3285c2248fc9SDouglas Gilbert 	if (scsi_debug_lbp())
328644d92694SMartin K. Petersen 		mapped = map_state(lba, &num);
3287c2248fc9SDouglas Gilbert 	else {
3288c2248fc9SDouglas Gilbert 		mapped = 1;
3289c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
3290c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
3291c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
3292c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
3293c2248fc9SDouglas Gilbert 		else
3294c2248fc9SDouglas Gilbert 			num = 0xffffffff;
3295c2248fc9SDouglas Gilbert 	}
329644d92694SMartin K. Petersen 
329744d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
3298c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
3299c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
3300c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
3301c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
330244d92694SMartin K. Petersen 
3303c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
330444d92694SMartin K. Petersen }
330544d92694SMartin K. Petersen 
3306fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
3307fb0cc8d1SDouglas Gilbert 
33088d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
33098d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
33108d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
33118d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
33128d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
33138d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
33148d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
33158d039e22SDouglas Gilbert  */
33161da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
33171da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
33181da177e4SLinus Torvalds {
331901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
33208d039e22SDouglas Gilbert 	unsigned int alloc_len;
33218d039e22SDouglas Gilbert 	unsigned char select_report;
33228d039e22SDouglas Gilbert 	u64 lun;
33238d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
3324fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
33258d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
33268d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
33278d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
33288d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
3329fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
3330fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
3331fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
33321da177e4SLinus Torvalds 
333319c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
33348d039e22SDouglas Gilbert 
33358d039e22SDouglas Gilbert 	select_report = cmd[2];
33368d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
33378d039e22SDouglas Gilbert 
33388d039e22SDouglas Gilbert 	if (alloc_len < 4) {
33398d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
33408d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
33411da177e4SLinus Torvalds 		return check_condition_result;
33421da177e4SLinus Torvalds 	}
33438d039e22SDouglas Gilbert 
33448d039e22SDouglas Gilbert 	switch (select_report) {
33458d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
3346773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
33478d039e22SDouglas Gilbert 		wlun_cnt = 0;
33488d039e22SDouglas Gilbert 		break;
33498d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
3350c65b1445SDouglas Gilbert 		lun_cnt = 0;
33518d039e22SDouglas Gilbert 		wlun_cnt = 1;
33528d039e22SDouglas Gilbert 		break;
33538d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
33548d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
33558d039e22SDouglas Gilbert 		wlun_cnt = 1;
33568d039e22SDouglas Gilbert 		break;
33578d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
33588d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
33598d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
33608d039e22SDouglas Gilbert 	default:
33618d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
33628d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
33638d039e22SDouglas Gilbert 		return check_condition_result;
33648d039e22SDouglas Gilbert 	}
33658d039e22SDouglas Gilbert 
33668d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
3367c65b1445SDouglas Gilbert 		--lun_cnt;
33688d039e22SDouglas Gilbert 
33698d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
3370fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
3371fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
33728d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
33738d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
33748d039e22SDouglas Gilbert 
3375fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
33768d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
3377fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3378fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
3379fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
3380fb0cc8d1SDouglas Gilbert 		if (k == 0) {
3381fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
3382fb0cc8d1SDouglas Gilbert 			++lun_p;
3383fb0cc8d1SDouglas Gilbert 			j = 1;
3384fb0cc8d1SDouglas Gilbert 		}
3385fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3386fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3387fb0cc8d1SDouglas Gilbert 				break;
3388fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
3389fb0cc8d1SDouglas Gilbert 		}
3390fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
3391fb0cc8d1SDouglas Gilbert 			break;
3392fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
3393fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3394fb0cc8d1SDouglas Gilbert 		if (res)
3395fb0cc8d1SDouglas Gilbert 			return res;
3396fb0cc8d1SDouglas Gilbert 		off_rsp += n;
3397fb0cc8d1SDouglas Gilbert 	}
3398fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
3399fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3400fb0cc8d1SDouglas Gilbert 		++j;
3401fb0cc8d1SDouglas Gilbert 	}
3402fb0cc8d1SDouglas Gilbert 	if (j > 0)
3403fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
34048d039e22SDouglas Gilbert 	return res;
34051da177e4SLinus Torvalds }
34061da177e4SLinus Torvalds 
3407c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3408c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
3409c639d14eSFUJITA Tomonori {
3410be4e11beSAkinobu Mita 	int j;
3411c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
3412c639d14eSFUJITA Tomonori 	unsigned int offset;
3413c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
3414be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3415c639d14eSFUJITA Tomonori 
3416c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
3417b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3418c5af0db9SAkinobu Mita 	if (!buf) {
341922017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
342022017ed2SDouglas Gilbert 				INSUFF_RES_ASCQ);
3421c5af0db9SAkinobu Mita 		return check_condition_result;
3422c5af0db9SAkinobu Mita 	}
3423c639d14eSFUJITA Tomonori 
342421a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
3425c639d14eSFUJITA Tomonori 
3426c639d14eSFUJITA Tomonori 	offset = 0;
3427be4e11beSAkinobu Mita 	sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3428be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_TO_SG);
3429c639d14eSFUJITA Tomonori 
3430be4e11beSAkinobu Mita 	while (sg_miter_next(&miter)) {
3431be4e11beSAkinobu Mita 		kaddr = miter.addr;
3432be4e11beSAkinobu Mita 		for (j = 0; j < miter.length; j++)
3433be4e11beSAkinobu Mita 			*(kaddr + j) ^= *(buf + offset + j);
3434c639d14eSFUJITA Tomonori 
3435be4e11beSAkinobu Mita 		offset += miter.length;
3436c639d14eSFUJITA Tomonori 	}
3437be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3438c639d14eSFUJITA Tomonori 	kfree(buf);
3439c639d14eSFUJITA Tomonori 
3440be4e11beSAkinobu Mita 	return 0;
3441c639d14eSFUJITA Tomonori }
3442c639d14eSFUJITA Tomonori 
3443fd32119bSDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3444fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
3445c2248fc9SDouglas Gilbert {
3446c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3447c2248fc9SDouglas Gilbert 	u64 lba;
3448c2248fc9SDouglas Gilbert 	u32 num;
3449c2248fc9SDouglas Gilbert 	int errsts;
3450c2248fc9SDouglas Gilbert 
3451c2248fc9SDouglas Gilbert 	if (!scsi_bidi_cmnd(scp)) {
3452c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3453c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3454c2248fc9SDouglas Gilbert 		return check_condition_result;
3455c2248fc9SDouglas Gilbert 	}
3456c2248fc9SDouglas Gilbert 	errsts = resp_read_dt0(scp, devip);
3457c2248fc9SDouglas Gilbert 	if (errsts)
3458c2248fc9SDouglas Gilbert 		return errsts;
3459c2248fc9SDouglas Gilbert 	if (!(cmd[1] & 0x4)) {		/* DISABLE_WRITE is not set */
3460c2248fc9SDouglas Gilbert 		errsts = resp_write_dt0(scp, devip);
3461c2248fc9SDouglas Gilbert 		if (errsts)
3462c2248fc9SDouglas Gilbert 			return errsts;
3463c2248fc9SDouglas Gilbert 	}
3464c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3465c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3466c2248fc9SDouglas Gilbert 	return resp_xdwriteread(scp, lba, num, devip);
3467c2248fc9SDouglas Gilbert }
3468c2248fc9SDouglas Gilbert 
3469c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3470c4837394SDouglas Gilbert {
3471c4837394SDouglas Gilbert 	struct sdebug_queue *sqp = sdebug_q_arr;
3472c4837394SDouglas Gilbert 
3473c4837394SDouglas Gilbert 	if (sdebug_mq_active) {
3474c4837394SDouglas Gilbert 		u32 tag = blk_mq_unique_tag(cmnd->request);
3475c4837394SDouglas Gilbert 		u16 hwq = blk_mq_unique_tag_to_hwq(tag);
3476c4837394SDouglas Gilbert 
3477c4837394SDouglas Gilbert 		if (unlikely(hwq >= submit_queues)) {
3478c4837394SDouglas Gilbert 			pr_warn("Unexpected hwq=%d, apply modulo\n", hwq);
3479c4837394SDouglas Gilbert 			hwq %= submit_queues;
3480c4837394SDouglas Gilbert 		}
3481c4837394SDouglas Gilbert 		pr_debug("tag=%u, hwq=%d\n", tag, hwq);
3482c4837394SDouglas Gilbert 		return sqp + hwq;
3483c4837394SDouglas Gilbert 	} else
3484c4837394SDouglas Gilbert 		return sqp;
3485c4837394SDouglas Gilbert }
3486c4837394SDouglas Gilbert 
3487c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
3488fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
34891da177e4SLinus Torvalds {
3490c4837394SDouglas Gilbert 	int qc_idx;
3491cbf67842SDouglas Gilbert 	int retiring = 0;
34921da177e4SLinus Torvalds 	unsigned long iflags;
3493c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3494cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3495cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
3496cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
34971da177e4SLinus Torvalds 
3498c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
3499c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
3500c4837394SDouglas Gilbert 	if (sdebug_statistics) {
3501cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
3502c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3503c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
3504c4837394SDouglas Gilbert 	}
3505c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3506c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
35071da177e4SLinus Torvalds 		return;
35081da177e4SLinus Torvalds 	}
3509c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
3510c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
3511cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
3512b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
3513c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3514c4837394SDouglas Gilbert 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3515c4837394SDouglas Gilbert 		       sd_dp->sqa_idx, qc_idx);
35161da177e4SLinus Torvalds 		return;
35171da177e4SLinus Torvalds 	}
3518cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
3519f46eb0e9SDouglas Gilbert 	if (likely(devip))
3520cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
3521cbf67842SDouglas Gilbert 	else
3522c1287970STomas Winkler 		pr_err("devip=NULL\n");
3523f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
3524cbf67842SDouglas Gilbert 		retiring = 1;
3525cbf67842SDouglas Gilbert 
3526cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
3527c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3528c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3529c1287970STomas Winkler 		pr_err("Unexpected completion\n");
3530cbf67842SDouglas Gilbert 		return;
35311da177e4SLinus Torvalds 	}
35321da177e4SLinus Torvalds 
3533cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
3534cbf67842SDouglas Gilbert 		int k, retval;
3535cbf67842SDouglas Gilbert 
3536cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
3537c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
3538c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3539c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
3540cbf67842SDouglas Gilbert 			return;
3541cbf67842SDouglas Gilbert 		}
3542c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
3543773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
3544cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3545cbf67842SDouglas Gilbert 		else
3546cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
3547cbf67842SDouglas Gilbert 	}
3548c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3549cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
3550cbf67842SDouglas Gilbert }
3551cbf67842SDouglas Gilbert 
3552cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
3553fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
3554cbf67842SDouglas Gilbert {
3555a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3556a10bc12aSDouglas Gilbert 						  hrt);
3557a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3558cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
3559cbf67842SDouglas Gilbert }
35601da177e4SLinus Torvalds 
3561a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
3562fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
3563a10bc12aSDouglas Gilbert {
3564a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3565a10bc12aSDouglas Gilbert 						  ew.work);
3566a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3567a10bc12aSDouglas Gilbert }
3568a10bc12aSDouglas Gilbert 
356909ba24c1SDouglas Gilbert static bool got_shared_uuid;
3570bf476433SChristoph Hellwig static uuid_t shared_uuid;
357109ba24c1SDouglas Gilbert 
3572fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
3573fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
35745cb2fc06SFUJITA Tomonori {
35755cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
35765cb2fc06SFUJITA Tomonori 
35775cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
35785cb2fc06SFUJITA Tomonori 	if (devip) {
357909ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
3580bf476433SChristoph Hellwig 			uuid_gen(&devip->lu_name);
358109ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
358209ba24c1SDouglas Gilbert 			if (got_shared_uuid)
358309ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
358409ba24c1SDouglas Gilbert 			else {
3585bf476433SChristoph Hellwig 				uuid_gen(&shared_uuid);
358609ba24c1SDouglas Gilbert 				got_shared_uuid = true;
358709ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
358809ba24c1SDouglas Gilbert 			}
358909ba24c1SDouglas Gilbert 		}
35905cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
35915cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
35925cb2fc06SFUJITA Tomonori 	}
35935cb2fc06SFUJITA Tomonori 	return devip;
35945cb2fc06SFUJITA Tomonori }
35955cb2fc06SFUJITA Tomonori 
3596f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
35971da177e4SLinus Torvalds {
35981da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
35991da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
3600f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
36011da177e4SLinus Torvalds 
3602d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
36031da177e4SLinus Torvalds 	if (!sdbg_host) {
3604c1287970STomas Winkler 		pr_err("Host info NULL\n");
36051da177e4SLinus Torvalds 		return NULL;
36061da177e4SLinus Torvalds         }
36071da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
36081da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
36091da177e4SLinus Torvalds                     (devip->target == sdev->id) &&
36101da177e4SLinus Torvalds                     (devip->lun == sdev->lun))
36111da177e4SLinus Torvalds                         return devip;
36121da177e4SLinus Torvalds 		else {
36131da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
36141da177e4SLinus Torvalds 				open_devip = devip;
36151da177e4SLinus Torvalds 		}
36161da177e4SLinus Torvalds 	}
36175cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
36185cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
36195cb2fc06SFUJITA Tomonori 		if (!open_devip) {
3620c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
36211da177e4SLinus Torvalds 			return NULL;
36221da177e4SLinus Torvalds 		}
36231da177e4SLinus Torvalds 	}
3624a75869d1SFUJITA Tomonori 
36251da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
36261da177e4SLinus Torvalds 	open_devip->target = sdev->id;
36271da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
36281da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
3629cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
3630cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
3631c2248fc9SDouglas Gilbert 	open_devip->used = true;
36321da177e4SLinus Torvalds 	return open_devip;
36331da177e4SLinus Torvalds }
36341da177e4SLinus Torvalds 
36358dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
36361da177e4SLinus Torvalds {
3637773642d9SDouglas Gilbert 	if (sdebug_verbose)
3638c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
36398dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
364075ad23bcSNick Piggin 	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
36418dea0d02SFUJITA Tomonori 	return 0;
36428dea0d02SFUJITA Tomonori }
36431da177e4SLinus Torvalds 
36448dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
36458dea0d02SFUJITA Tomonori {
3646f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
3647f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
3648a34c4e98SFUJITA Tomonori 
3649773642d9SDouglas Gilbert 	if (sdebug_verbose)
3650c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
36518dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3652b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3653b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3654b01f6f83SDouglas Gilbert 	if (devip == NULL) {
3655f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
3656b01f6f83SDouglas Gilbert 		if (devip == NULL)
36578dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
3658f46eb0e9SDouglas Gilbert 	}
3659c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
36606bb5e6e7SAkinobu Mita 	blk_queue_max_segment_size(sdp->request_queue, -1U);
3661773642d9SDouglas Gilbert 	if (sdebug_no_uld)
366278d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
36638dea0d02SFUJITA Tomonori 	return 0;
36648dea0d02SFUJITA Tomonori }
36658dea0d02SFUJITA Tomonori 
36668dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
36678dea0d02SFUJITA Tomonori {
36688dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
36698dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
36708dea0d02SFUJITA Tomonori 
3671773642d9SDouglas Gilbert 	if (sdebug_verbose)
3672c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
36738dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
36748dea0d02SFUJITA Tomonori 	if (devip) {
367525985edcSLucas De Marchi 		/* make this slot available for re-use */
3676c2248fc9SDouglas Gilbert 		devip->used = false;
36778dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
36788dea0d02SFUJITA Tomonori 	}
36798dea0d02SFUJITA Tomonori }
36808dea0d02SFUJITA Tomonori 
3681c4837394SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp)
3682c4837394SDouglas Gilbert {
3683c4837394SDouglas Gilbert 	if (!sd_dp)
3684c4837394SDouglas Gilbert 		return;
3685c4837394SDouglas Gilbert 	if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0))
3686c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
3687c4837394SDouglas Gilbert 	else if (sdebug_jdelay < 0)
3688c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
3689c4837394SDouglas Gilbert }
3690c4837394SDouglas Gilbert 
3691a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
3692a10bc12aSDouglas Gilbert    returns false */
3693a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
36948dea0d02SFUJITA Tomonori {
36958dea0d02SFUJITA Tomonori 	unsigned long iflags;
3696c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
3697c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
36988dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3699cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3700a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
37018dea0d02SFUJITA Tomonori 
3702c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3703c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
3704773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
3705cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
3706cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
3707cbf67842SDouglas Gilbert 			qmax = r_qmax;
3708cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
3709c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
3710c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
3711a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
3712a10bc12aSDouglas Gilbert 					continue;
3713c4837394SDouglas Gilbert 				/* found */
3714db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3715db525fceSDouglas Gilbert 						cmnd->device->hostdata;
3716db525fceSDouglas Gilbert 				if (devip)
3717db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3718db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3719a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
3720c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3721c4837394SDouglas Gilbert 				stop_qc_helper(sd_dp);
3722c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
3723a10bc12aSDouglas Gilbert 				return true;
37248dea0d02SFUJITA Tomonori 			}
3725cbf67842SDouglas Gilbert 		}
3726c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3727c4837394SDouglas Gilbert 	}
3728a10bc12aSDouglas Gilbert 	return false;
37298dea0d02SFUJITA Tomonori }
37308dea0d02SFUJITA Tomonori 
3731a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
37328dea0d02SFUJITA Tomonori static void stop_all_queued(void)
37338dea0d02SFUJITA Tomonori {
37348dea0d02SFUJITA Tomonori 	unsigned long iflags;
3735c4837394SDouglas Gilbert 	int j, k;
3736c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
37378dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3738cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3739a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
37408dea0d02SFUJITA Tomonori 
3741c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3742c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
3743c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3744c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
3745c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
3746c4837394SDouglas Gilbert 				if (sqcp->a_cmnd == NULL)
3747a10bc12aSDouglas Gilbert 					continue;
3748db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3749db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
3750db525fceSDouglas Gilbert 				if (devip)
3751db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3752db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3753a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
3754c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3755c4837394SDouglas Gilbert 				stop_qc_helper(sd_dp);
3756c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
3757c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
37588dea0d02SFUJITA Tomonori 			}
37598dea0d02SFUJITA Tomonori 		}
3760c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3761c4837394SDouglas Gilbert 	}
3762cbf67842SDouglas Gilbert }
3763cbf67842SDouglas Gilbert 
3764cbf67842SDouglas Gilbert /* Free queued command memory on heap */
3765cbf67842SDouglas Gilbert static void free_all_queued(void)
3766cbf67842SDouglas Gilbert {
3767c4837394SDouglas Gilbert 	int j, k;
3768c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3769cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3770cbf67842SDouglas Gilbert 
3771c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3772c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3773c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
3774a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
3775a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
3776cbf67842SDouglas Gilbert 		}
37771da177e4SLinus Torvalds 	}
3778c4837394SDouglas Gilbert }
37791da177e4SLinus Torvalds 
37801da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
37811da177e4SLinus Torvalds {
3782a10bc12aSDouglas Gilbert 	bool ok;
3783a10bc12aSDouglas Gilbert 
37841da177e4SLinus Torvalds 	++num_aborts;
3785cbf67842SDouglas Gilbert 	if (SCpnt) {
3786a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
3787a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3788a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
3789a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
3790a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
3791cbf67842SDouglas Gilbert 	}
37921da177e4SLinus Torvalds 	return SUCCESS;
37931da177e4SLinus Torvalds }
37941da177e4SLinus Torvalds 
37951da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
37961da177e4SLinus Torvalds {
37971da177e4SLinus Torvalds 	++num_dev_resets;
3798cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
3799cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
3800f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
3801f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
3802cbf67842SDouglas Gilbert 
3803773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3804cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
38051da177e4SLinus Torvalds 		if (devip)
3806cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
38071da177e4SLinus Torvalds 	}
38081da177e4SLinus Torvalds 	return SUCCESS;
38091da177e4SLinus Torvalds }
38101da177e4SLinus Torvalds 
3811cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3812cbf67842SDouglas Gilbert {
3813cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
3814cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3815cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
3816cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
3817cbf67842SDouglas Gilbert 	int k = 0;
3818cbf67842SDouglas Gilbert 
3819cbf67842SDouglas Gilbert 	++num_target_resets;
3820cbf67842SDouglas Gilbert 	if (!SCpnt)
3821cbf67842SDouglas Gilbert 		goto lie;
3822cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
3823cbf67842SDouglas Gilbert 	if (!sdp)
3824cbf67842SDouglas Gilbert 		goto lie;
3825773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3826cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3827cbf67842SDouglas Gilbert 	hp = sdp->host;
3828cbf67842SDouglas Gilbert 	if (!hp)
3829cbf67842SDouglas Gilbert 		goto lie;
3830cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3831cbf67842SDouglas Gilbert 	if (sdbg_host) {
3832cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
3833cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
3834cbf67842SDouglas Gilbert 				    dev_list)
3835cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
3836cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3837cbf67842SDouglas Gilbert 				++k;
3838cbf67842SDouglas Gilbert 			}
3839cbf67842SDouglas Gilbert 	}
3840773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3841cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3842cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
3843cbf67842SDouglas Gilbert lie:
3844cbf67842SDouglas Gilbert 	return SUCCESS;
3845cbf67842SDouglas Gilbert }
3846cbf67842SDouglas Gilbert 
38471da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
38481da177e4SLinus Torvalds {
38491da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
3850cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
38511da177e4SLinus Torvalds         struct scsi_device * sdp;
38521da177e4SLinus Torvalds         struct Scsi_Host * hp;
3853cbf67842SDouglas Gilbert 	int k = 0;
38541da177e4SLinus Torvalds 
38551da177e4SLinus Torvalds 	++num_bus_resets;
3856cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
3857cbf67842SDouglas Gilbert 		goto lie;
3858cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
3859773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3860cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3861cbf67842SDouglas Gilbert 	hp = sdp->host;
3862cbf67842SDouglas Gilbert 	if (hp) {
3863d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
38641da177e4SLinus Torvalds 		if (sdbg_host) {
3865cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
38661da177e4SLinus Torvalds                                             &sdbg_host->dev_info_list,
3867cbf67842SDouglas Gilbert 					    dev_list) {
3868cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3869cbf67842SDouglas Gilbert 				++k;
38701da177e4SLinus Torvalds 			}
38711da177e4SLinus Torvalds 		}
3872cbf67842SDouglas Gilbert 	}
3873773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3874cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3875cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
3876cbf67842SDouglas Gilbert lie:
38771da177e4SLinus Torvalds 	return SUCCESS;
38781da177e4SLinus Torvalds }
38791da177e4SLinus Torvalds 
38801da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
38811da177e4SLinus Torvalds {
38821da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
3883cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3884cbf67842SDouglas Gilbert 	int k = 0;
38851da177e4SLinus Torvalds 
38861da177e4SLinus Torvalds 	++num_host_resets;
3887773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3888cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
38891da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
38901da177e4SLinus Torvalds         list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3891cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
3892cbf67842SDouglas Gilbert 				    dev_list) {
3893cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3894cbf67842SDouglas Gilbert 			++k;
3895cbf67842SDouglas Gilbert 		}
38961da177e4SLinus Torvalds         }
38971da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
38981da177e4SLinus Torvalds 	stop_all_queued();
3899773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3900cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
3901cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
39021da177e4SLinus Torvalds 	return SUCCESS;
39031da177e4SLinus Torvalds }
39041da177e4SLinus Torvalds 
3905f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
39065f2578e5SFUJITA Tomonori 				      unsigned long store_size)
39071da177e4SLinus Torvalds {
39081da177e4SLinus Torvalds 	struct partition * pp;
39091da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
39101da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
39111da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
39121da177e4SLinus Torvalds 
39131da177e4SLinus Torvalds 	/* assume partition table already zeroed */
3914773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
39151da177e4SLinus Torvalds 		return;
3916773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
3917773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
3918c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
39191da177e4SLinus Torvalds 	}
3920c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
39211da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
3922773642d9SDouglas Gilbert 			   / sdebug_num_parts;
39231da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
39241da177e4SLinus Torvalds         starts[0] = sdebug_sectors_per;
3925773642d9SDouglas Gilbert 	for (k = 1; k < sdebug_num_parts; ++k)
39261da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
39271da177e4SLinus Torvalds 			    * heads_by_sects;
3928773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
3929773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
39301da177e4SLinus Torvalds 
39311da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
39321da177e4SLinus Torvalds 	ramp[511] = 0xAA;
39331da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
39341da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
39351da177e4SLinus Torvalds 		start_sec = starts[k];
39361da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
39371da177e4SLinus Torvalds 		pp->boot_ind = 0;
39381da177e4SLinus Torvalds 
39391da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
39401da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
39411da177e4SLinus Torvalds 			   / sdebug_sectors_per;
39421da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
39431da177e4SLinus Torvalds 
39441da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
39451da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
39461da177e4SLinus Torvalds 			       / sdebug_sectors_per;
39471da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
39481da177e4SLinus Torvalds 
3949150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
3950150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
39511da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
39521da177e4SLinus Torvalds 	}
39531da177e4SLinus Torvalds }
39541da177e4SLinus Torvalds 
3955c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block)
3956c4837394SDouglas Gilbert {
3957c4837394SDouglas Gilbert 	int j;
3958c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3959c4837394SDouglas Gilbert 
3960c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
3961c4837394SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)block);
3962c4837394SDouglas Gilbert }
3963c4837394SDouglas Gilbert 
3964c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
3965c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
3966c4837394SDouglas Gilbert  */
3967c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
3968c4837394SDouglas Gilbert {
3969c4837394SDouglas Gilbert 	int count, modulo;
3970c4837394SDouglas Gilbert 
3971c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
3972c4837394SDouglas Gilbert 	if (modulo < 2)
3973c4837394SDouglas Gilbert 		return;
3974c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
3975c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
3976c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
3977c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
3978c4837394SDouglas Gilbert }
3979c4837394SDouglas Gilbert 
3980c4837394SDouglas Gilbert static void clear_queue_stats(void)
3981c4837394SDouglas Gilbert {
3982c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
3983c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
3984c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
3985c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
3986c4837394SDouglas Gilbert }
3987c4837394SDouglas Gilbert 
3988c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp,
3989c4837394SDouglas Gilbert 			 struct sdebug_queued_cmd *sqcp)
3990c4837394SDouglas Gilbert {
3991c4837394SDouglas Gilbert 	if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0)
3992c4837394SDouglas Gilbert 		return;
3993c4837394SDouglas Gilbert 	sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
3994c4837394SDouglas Gilbert 	sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
3995c4837394SDouglas Gilbert 	sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
3996c4837394SDouglas Gilbert 	sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
3997c4837394SDouglas Gilbert 	sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
3998c4837394SDouglas Gilbert }
3999c4837394SDouglas Gilbert 
4000c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
4001c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
4002c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
4003c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
4004c4837394SDouglas Gilbert  */
4005fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
4006cbf67842SDouglas Gilbert 			 int scsi_result, int delta_jiff)
40071da177e4SLinus Torvalds {
4008cbf67842SDouglas Gilbert 	unsigned long iflags;
4009cd62b7daSDouglas Gilbert 	int k, num_in_q, qdepth, inject;
4010c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4011c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4012299b6c07STomas Winkler 	struct scsi_device *sdp;
4013a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
40141da177e4SLinus Torvalds 
4015b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
4016b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
4017f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
4018f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
40191da177e4SLinus Torvalds 	}
4020299b6c07STomas Winkler 	sdp = cmnd->device;
4021299b6c07STomas Winkler 
4022f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose && scsi_result))
4023cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4024cbf67842SDouglas Gilbert 			    __func__, scsi_result);
4025cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
4026cd62b7daSDouglas Gilbert 		goto respond_in_thread;
40271da177e4SLinus Torvalds 
4028cd62b7daSDouglas Gilbert 	/* schedule the response at a later time if resources permit */
4029c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
4030c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
4031c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
4032c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4033c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
4034c4837394SDouglas Gilbert 	}
4035cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
4036cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
4037cbf67842SDouglas Gilbert 	inject = 0;
4038f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
4039cd62b7daSDouglas Gilbert 		if (scsi_result) {
4040c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4041cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4042cd62b7daSDouglas Gilbert 		} else
4043cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4044c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
4045773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4046f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
4047cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
4048cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
4049773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
4050cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
4051cbf67842SDouglas Gilbert 			inject = 1;
4052cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
40531da177e4SLinus Torvalds 		}
4054cbf67842SDouglas Gilbert 	}
4055cbf67842SDouglas Gilbert 
4056c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
4057f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
4058c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4059cd62b7daSDouglas Gilbert 		if (scsi_result)
4060cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4061773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
4062cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4063773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
4064cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
4065cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
4066773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
4067cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
4068cbf67842SDouglas Gilbert 						    "report: host busy"));
4069cd62b7daSDouglas Gilbert 		if (scsi_result)
4070cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4071cd62b7daSDouglas Gilbert 		else
4072cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
40731da177e4SLinus Torvalds 	}
4074c4837394SDouglas Gilbert 	__set_bit(k, sqp->in_use_bm);
4075cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
4076c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
40771da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
4078c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
4079cbf67842SDouglas Gilbert 	cmnd->result = scsi_result;
4080a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
4081c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4082c4837394SDouglas Gilbert 	if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4083c4837394SDouglas Gilbert 		setup_inject(sqp, sqcp);
4084b01f6f83SDouglas Gilbert 	if (delta_jiff > 0 || sdebug_ndelay > 0) {
4085b333a819SDouglas Gilbert 		ktime_t kt;
4086cbf67842SDouglas Gilbert 
4087b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
4088b333a819SDouglas Gilbert 			struct timespec ts;
4089b333a819SDouglas Gilbert 
4090b333a819SDouglas Gilbert 			jiffies_to_timespec(delta_jiff, &ts);
4091b333a819SDouglas Gilbert 			kt = ktime_set(ts.tv_sec, ts.tv_nsec);
4092b333a819SDouglas Gilbert 		} else
40938b0e1953SThomas Gleixner 			kt = sdebug_ndelay;
4094a10bc12aSDouglas Gilbert 		if (NULL == sd_dp) {
4095a10bc12aSDouglas Gilbert 			sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
4096a10bc12aSDouglas Gilbert 			if (NULL == sd_dp)
4097cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
4098a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4099a10bc12aSDouglas Gilbert 			hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
4100c4837394SDouglas Gilbert 				     HRTIMER_MODE_REL_PINNED);
4101a10bc12aSDouglas Gilbert 			sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
4102c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4103c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4104cbf67842SDouglas Gilbert 		}
4105c4837394SDouglas Gilbert 		if (sdebug_statistics)
4106c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
4107c4837394SDouglas Gilbert 		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4108c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
4109a10bc12aSDouglas Gilbert 		if (NULL == sd_dp) {
4110a10bc12aSDouglas Gilbert 			sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC);
4111a10bc12aSDouglas Gilbert 			if (NULL == sd_dp)
4112cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
4113a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4114c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4115c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4116a10bc12aSDouglas Gilbert 			INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
4117cbf67842SDouglas Gilbert 		}
4118c4837394SDouglas Gilbert 		if (sdebug_statistics)
4119c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
4120a10bc12aSDouglas Gilbert 		schedule_work(&sd_dp->ew.work);
4121cbf67842SDouglas Gilbert 	}
4122f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4123f46eb0e9SDouglas Gilbert 		     (scsi_result == device_qfull_result)))
4124cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4125cbf67842SDouglas Gilbert 			    "%s: num_in_q=%d +1, %s%s\n", __func__,
4126cbf67842SDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""),
4127cbf67842SDouglas Gilbert 			    "status: TASK SET FULL");
41281da177e4SLinus Torvalds 	return 0;
4129cd62b7daSDouglas Gilbert 
4130cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
4131cd62b7daSDouglas Gilbert 	cmnd->result = scsi_result;
4132cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
4133cd62b7daSDouglas Gilbert 	return 0;
41341da177e4SLinus Torvalds }
4135cbf67842SDouglas Gilbert 
413623183910SDouglas Gilbert /* Note: The following macros create attribute files in the
413723183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
413823183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
413923183910SDouglas Gilbert    as it can when the corresponding attribute in the
414023183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
414123183910SDouglas Gilbert  */
4142773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4143773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
4144773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
4145c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
4146773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4147773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
4148773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
4149773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4150773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4151773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4152773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4153773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
4154e5203cf0SHannes Reinecke module_param_string(inq_vendor, sdebug_inq_vendor_id,
4155e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR);
4156e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id,
4157e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR);
4158e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev,
4159e5203cf0SHannes Reinecke 		    sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR);
4160773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4161773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4162773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4163773642d9SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4164773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4165773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4166773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4167773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4168773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4169773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4170773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4171773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4172773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4173773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4174773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
417586e6828aSLukas Herbolt module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
4176773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4177773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4178773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4179773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
4180c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
4181773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
4182c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
4183773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4184773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4185773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4186773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4187773642d9SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
418809ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
4189773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
419023183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
4191773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
41925b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
41931da177e4SLinus Torvalds 
41941da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
41951da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
41961da177e4SLinus Torvalds MODULE_LICENSE("GPL");
4197b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
41981da177e4SLinus Torvalds 
41991da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
42005b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
42010759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
4202cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
4203c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
42045b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
42055b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
4206c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
4207beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
420823183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
42095b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
4210185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
4211e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
4212e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
4213e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\"0186\")");
42145b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
42155b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
42165b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
4217760f3b03SDouglas Gilbert MODULE_PARM_DESC(lbprz,
4218760f3b03SDouglas Gilbert 	"on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
42195b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
4220c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
4221cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4222cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
4223c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
422478d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
42251da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
4226c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
422732c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
42286f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
42295b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
423086e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
42311da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
4232d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
4233760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
4234ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
4235c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
4236c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
4237c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
42385b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
42395b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
42406014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
42416014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
424209ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
424309ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
4244c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
42455b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
42465b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
42471da177e4SLinus Torvalds 
4248760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
4249760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
42501da177e4SLinus Torvalds 
42511da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp)
42521da177e4SLinus Torvalds {
4253c4837394SDouglas Gilbert 	int k;
4254c4837394SDouglas Gilbert 
4255760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4256760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
4257760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
4258c4837394SDouglas Gilbert 		return sdebug_info;
4259760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4260760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4261760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
4262760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
42631da177e4SLinus Torvalds 	return sdebug_info;
42641da177e4SLinus Torvalds }
42651da177e4SLinus Torvalds 
4266cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
4267fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4268fd32119bSDouglas Gilbert 				 int length)
42691da177e4SLinus Torvalds {
42701da177e4SLinus Torvalds 	char arr[16];
4271c8ed555aSAl Viro 	int opts;
42721da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
42731da177e4SLinus Torvalds 
42741da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
42751da177e4SLinus Torvalds 		return -EACCES;
42761da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
42771da177e4SLinus Torvalds 	arr[minLen] = '\0';
4278c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
42791da177e4SLinus Torvalds 		return -EINVAL;
4280773642d9SDouglas Gilbert 	sdebug_opts = opts;
4281773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4282773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4283773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
4284c4837394SDouglas Gilbert 		tweak_cmnd_count();
42851da177e4SLinus Torvalds 	return length;
42861da177e4SLinus Torvalds }
4287c8ed555aSAl Viro 
4288cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4289cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
4290cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
4291c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4292c8ed555aSAl Viro {
4293c4837394SDouglas Gilbert 	int f, j, l;
4294c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4295cbf67842SDouglas Gilbert 
4296c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4297c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
4298c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4299c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4300c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
4301c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4302c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4303c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
4304c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4305c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4306c4837394SDouglas Gilbert 		   num_aborts);
4307c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4308c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
4309c4837394SDouglas Gilbert 		   num_host_resets);
4310c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4311c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
4312c4837394SDouglas Gilbert 	seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n",
4313c4837394SDouglas Gilbert 		   TICK_NSEC / 1000, "statistics", sdebug_statistics,
4314c4837394SDouglas Gilbert 		   sdebug_mq_active);
4315c4837394SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4316c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
4317c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
4318c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
4319c4837394SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf));
4320cbf67842SDouglas Gilbert 
4321c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
4322c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4323c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
4324c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4325773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
4326c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4327c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
4328c4837394SDouglas Gilbert 				   "first,last bits", f, l);
4329c4837394SDouglas Gilbert 		}
4330cbf67842SDouglas Gilbert 	}
4331c8ed555aSAl Viro 	return 0;
43321da177e4SLinus Torvalds }
43331da177e4SLinus Torvalds 
433482069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
43351da177e4SLinus Torvalds {
4336c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
43371da177e4SLinus Torvalds }
4338c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4339c4837394SDouglas Gilbert  * of delay is jiffies.
4340c4837394SDouglas Gilbert  */
434182069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
434282069379SAkinobu Mita 			   size_t count)
43431da177e4SLinus Torvalds {
4344c2206098SDouglas Gilbert 	int jdelay, res;
43451da177e4SLinus Torvalds 
4346b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
4347cbf67842SDouglas Gilbert 		res = count;
4348c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
4349c4837394SDouglas Gilbert 			int j, k;
4350c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4351cbf67842SDouglas Gilbert 
4352c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4353c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4354c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4355c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4356c4837394SDouglas Gilbert 						   sdebug_max_queue);
4357c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4358c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4359c4837394SDouglas Gilbert 					break;
4360c4837394SDouglas Gilbert 				}
4361c4837394SDouglas Gilbert 			}
4362c4837394SDouglas Gilbert 			if (res > 0) {
4363a10bc12aSDouglas Gilbert 				/* make sure sdebug_defer instances get
4364a10bc12aSDouglas Gilbert 				 * re-allocated for new delay variant */
4365a10bc12aSDouglas Gilbert 				free_all_queued();
4366c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
4367773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
43681da177e4SLinus Torvalds 			}
4369c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4370cbf67842SDouglas Gilbert 		}
4371cbf67842SDouglas Gilbert 		return res;
43721da177e4SLinus Torvalds 	}
43731da177e4SLinus Torvalds 	return -EINVAL;
43741da177e4SLinus Torvalds }
437582069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
43761da177e4SLinus Torvalds 
4377cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4378cbf67842SDouglas Gilbert {
4379773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
4380cbf67842SDouglas Gilbert }
4381cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
4382c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
4383cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
4384cbf67842SDouglas Gilbert 			    size_t count)
4385cbf67842SDouglas Gilbert {
4386c4837394SDouglas Gilbert 	int ndelay, res;
4387cbf67842SDouglas Gilbert 
4388cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4389c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
4390cbf67842SDouglas Gilbert 		res = count;
4391773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
4392c4837394SDouglas Gilbert 			int j, k;
4393c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4394c4837394SDouglas Gilbert 
4395c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4396c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4397c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4398c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4399c4837394SDouglas Gilbert 						   sdebug_max_queue);
4400c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4401c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4402c4837394SDouglas Gilbert 					break;
4403c4837394SDouglas Gilbert 				}
4404c4837394SDouglas Gilbert 			}
4405c4837394SDouglas Gilbert 			if (res > 0) {
4406a10bc12aSDouglas Gilbert 				/* make sure sdebug_defer instances get
4407a10bc12aSDouglas Gilbert 				 * re-allocated for new delay variant */
4408a10bc12aSDouglas Gilbert 				free_all_queued();
4409773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
4410c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
4411c2206098SDouglas Gilbert 							: DEF_JDELAY;
4412cbf67842SDouglas Gilbert 			}
4413c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4414cbf67842SDouglas Gilbert 		}
4415cbf67842SDouglas Gilbert 		return res;
4416cbf67842SDouglas Gilbert 	}
4417cbf67842SDouglas Gilbert 	return -EINVAL;
4418cbf67842SDouglas Gilbert }
4419cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
4420cbf67842SDouglas Gilbert 
442182069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
44221da177e4SLinus Torvalds {
4423773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
44241da177e4SLinus Torvalds }
44251da177e4SLinus Torvalds 
442682069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
442782069379SAkinobu Mita 			  size_t count)
44281da177e4SLinus Torvalds {
44291da177e4SLinus Torvalds         int opts;
44301da177e4SLinus Torvalds 	char work[20];
44311da177e4SLinus Torvalds 
44321da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
443348a96876SRasmus Villemoes 		if (0 == strncasecmp(work,"0x", 2)) {
44341da177e4SLinus Torvalds 			if (1 == sscanf(&work[2], "%x", &opts))
44351da177e4SLinus Torvalds 				goto opts_done;
44361da177e4SLinus Torvalds 		} else {
44371da177e4SLinus Torvalds 			if (1 == sscanf(work, "%d", &opts))
44381da177e4SLinus Torvalds 				goto opts_done;
44391da177e4SLinus Torvalds 		}
44401da177e4SLinus Torvalds 	}
44411da177e4SLinus Torvalds 	return -EINVAL;
44421da177e4SLinus Torvalds opts_done:
4443773642d9SDouglas Gilbert 	sdebug_opts = opts;
4444773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4445773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4446c4837394SDouglas Gilbert 	tweak_cmnd_count();
44471da177e4SLinus Torvalds 	return count;
44481da177e4SLinus Torvalds }
444982069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
44501da177e4SLinus Torvalds 
445182069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
44521da177e4SLinus Torvalds {
4453773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
44541da177e4SLinus Torvalds }
445582069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
445682069379SAkinobu Mita 			   size_t count)
44571da177e4SLinus Torvalds {
44581da177e4SLinus Torvalds         int n;
44591da177e4SLinus Torvalds 
44601da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4461773642d9SDouglas Gilbert 		sdebug_ptype = n;
44621da177e4SLinus Torvalds 		return count;
44631da177e4SLinus Torvalds 	}
44641da177e4SLinus Torvalds 	return -EINVAL;
44651da177e4SLinus Torvalds }
446682069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
44671da177e4SLinus Torvalds 
446882069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
44691da177e4SLinus Torvalds {
4470773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
44711da177e4SLinus Torvalds }
447282069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
447382069379SAkinobu Mita 			    size_t count)
44741da177e4SLinus Torvalds {
44751da177e4SLinus Torvalds         int n;
44761da177e4SLinus Torvalds 
44771da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4478773642d9SDouglas Gilbert 		sdebug_dsense = n;
44791da177e4SLinus Torvalds 		return count;
44801da177e4SLinus Torvalds 	}
44811da177e4SLinus Torvalds 	return -EINVAL;
44821da177e4SLinus Torvalds }
448382069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
44841da177e4SLinus Torvalds 
448582069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
448623183910SDouglas Gilbert {
4487773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
448823183910SDouglas Gilbert }
448982069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
449082069379SAkinobu Mita 			     size_t count)
449123183910SDouglas Gilbert {
449223183910SDouglas Gilbert         int n;
449323183910SDouglas Gilbert 
449423183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4495cbf67842SDouglas Gilbert 		n = (n > 0);
4496773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
4497773642d9SDouglas Gilbert 		if (sdebug_fake_rw != n) {
4498cbf67842SDouglas Gilbert 			if ((0 == n) && (NULL == fake_storep)) {
4499cbf67842SDouglas Gilbert 				unsigned long sz =
4500773642d9SDouglas Gilbert 					(unsigned long)sdebug_dev_size_mb *
4501cbf67842SDouglas Gilbert 					1048576;
4502cbf67842SDouglas Gilbert 
4503cbf67842SDouglas Gilbert 				fake_storep = vmalloc(sz);
4504cbf67842SDouglas Gilbert 				if (NULL == fake_storep) {
4505c1287970STomas Winkler 					pr_err("out of memory, 9\n");
4506cbf67842SDouglas Gilbert 					return -ENOMEM;
4507cbf67842SDouglas Gilbert 				}
4508cbf67842SDouglas Gilbert 				memset(fake_storep, 0, sz);
4509cbf67842SDouglas Gilbert 			}
4510773642d9SDouglas Gilbert 			sdebug_fake_rw = n;
4511cbf67842SDouglas Gilbert 		}
451223183910SDouglas Gilbert 		return count;
451323183910SDouglas Gilbert 	}
451423183910SDouglas Gilbert 	return -EINVAL;
451523183910SDouglas Gilbert }
451682069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
451723183910SDouglas Gilbert 
451882069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
4519c65b1445SDouglas Gilbert {
4520773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
4521c65b1445SDouglas Gilbert }
452282069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
452382069379SAkinobu Mita 			      size_t count)
4524c65b1445SDouglas Gilbert {
4525c65b1445SDouglas Gilbert         int n;
4526c65b1445SDouglas Gilbert 
4527c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4528773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
4529c65b1445SDouglas Gilbert 		return count;
4530c65b1445SDouglas Gilbert 	}
4531c65b1445SDouglas Gilbert 	return -EINVAL;
4532c65b1445SDouglas Gilbert }
453382069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
4534c65b1445SDouglas Gilbert 
453582069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
45361da177e4SLinus Torvalds {
4537773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
45381da177e4SLinus Torvalds }
453982069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
454082069379SAkinobu Mita 			      size_t count)
45411da177e4SLinus Torvalds {
45421da177e4SLinus Torvalds         int n;
45431da177e4SLinus Torvalds 
45441da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4545773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
45461da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
45471da177e4SLinus Torvalds 		return count;
45481da177e4SLinus Torvalds 	}
45491da177e4SLinus Torvalds 	return -EINVAL;
45501da177e4SLinus Torvalds }
455182069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
45521da177e4SLinus Torvalds 
455382069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
45541da177e4SLinus Torvalds {
4555773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
45561da177e4SLinus Torvalds }
455782069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
45581da177e4SLinus Torvalds 
455982069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
45601da177e4SLinus Torvalds {
4561773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
45621da177e4SLinus Torvalds }
456382069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
45641da177e4SLinus Torvalds 
456582069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
45661da177e4SLinus Torvalds {
4567773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
45681da177e4SLinus Torvalds }
456982069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
457082069379SAkinobu Mita 			       size_t count)
45711da177e4SLinus Torvalds {
45721da177e4SLinus Torvalds         int nth;
45731da177e4SLinus Torvalds 
45741da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
4575773642d9SDouglas Gilbert 		sdebug_every_nth = nth;
4576c4837394SDouglas Gilbert 		if (nth && !sdebug_statistics) {
4577c4837394SDouglas Gilbert 			pr_info("every_nth needs statistics=1, set it\n");
4578c4837394SDouglas Gilbert 			sdebug_statistics = true;
4579c4837394SDouglas Gilbert 		}
4580c4837394SDouglas Gilbert 		tweak_cmnd_count();
45811da177e4SLinus Torvalds 		return count;
45821da177e4SLinus Torvalds 	}
45831da177e4SLinus Torvalds 	return -EINVAL;
45841da177e4SLinus Torvalds }
458582069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
45861da177e4SLinus Torvalds 
458782069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
45881da177e4SLinus Torvalds {
4589773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
45901da177e4SLinus Torvalds }
459182069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
459282069379SAkinobu Mita 			      size_t count)
45931da177e4SLinus Torvalds {
45941da177e4SLinus Torvalds         int n;
459519c8ead7SEwan D. Milne 	bool changed;
45961da177e4SLinus Torvalds 
45971da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
45988d039e22SDouglas Gilbert 		if (n > 256) {
45998d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
46008d039e22SDouglas Gilbert 			return -EINVAL;
46018d039e22SDouglas Gilbert 		}
4602773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
4603773642d9SDouglas Gilbert 		sdebug_max_luns = n;
46041da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
4605773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
460619c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
460719c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
460819c8ead7SEwan D. Milne 
460919c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
461019c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
461119c8ead7SEwan D. Milne 					    host_list) {
461219c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
461319c8ead7SEwan D. Milne 						    dev_list) {
461419c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
461519c8ead7SEwan D. Milne 						dp->uas_bm);
461619c8ead7SEwan D. Milne 				}
461719c8ead7SEwan D. Milne 			}
461819c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
461919c8ead7SEwan D. Milne 		}
46201da177e4SLinus Torvalds 		return count;
46211da177e4SLinus Torvalds 	}
46221da177e4SLinus Torvalds 	return -EINVAL;
46231da177e4SLinus Torvalds }
462482069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
46251da177e4SLinus Torvalds 
462682069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
462778d4e5a0SDouglas Gilbert {
4628773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
462978d4e5a0SDouglas Gilbert }
4630cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
4631cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
463282069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
463382069379SAkinobu Mita 			       size_t count)
463478d4e5a0SDouglas Gilbert {
4635c4837394SDouglas Gilbert 	int j, n, k, a;
4636c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
463778d4e5a0SDouglas Gilbert 
463878d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
4639c4837394SDouglas Gilbert 	    (n <= SDEBUG_CANQUEUE)) {
4640c4837394SDouglas Gilbert 		block_unblock_all_queues(true);
4641c4837394SDouglas Gilbert 		k = 0;
4642c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4643c4837394SDouglas Gilbert 		     ++j, ++sqp) {
4644c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4645c4837394SDouglas Gilbert 			if (a > k)
4646c4837394SDouglas Gilbert 				k = a;
4647c4837394SDouglas Gilbert 		}
4648773642d9SDouglas Gilbert 		sdebug_max_queue = n;
4649c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
4650cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4651cbf67842SDouglas Gilbert 		else if (k >= n)
4652cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4653cbf67842SDouglas Gilbert 		else
4654cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4655c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
465678d4e5a0SDouglas Gilbert 		return count;
465778d4e5a0SDouglas Gilbert 	}
465878d4e5a0SDouglas Gilbert 	return -EINVAL;
465978d4e5a0SDouglas Gilbert }
466082069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
466178d4e5a0SDouglas Gilbert 
466282069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
466378d4e5a0SDouglas Gilbert {
4664773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
466578d4e5a0SDouglas Gilbert }
466682069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
466778d4e5a0SDouglas Gilbert 
466882069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
46691da177e4SLinus Torvalds {
4670773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
46711da177e4SLinus Torvalds }
467282069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
46731da177e4SLinus Torvalds 
467482069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
4675c65b1445SDouglas Gilbert {
4676773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
4677c65b1445SDouglas Gilbert }
467882069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
467982069379SAkinobu Mita 				size_t count)
4680c65b1445SDouglas Gilbert {
4681c65b1445SDouglas Gilbert         int n;
46820d01c5dfSDouglas Gilbert 	bool changed;
4683c65b1445SDouglas Gilbert 
4684c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4685773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
4686773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
468728898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
46880d01c5dfSDouglas Gilbert 		if (changed) {
46890d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
46900d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
469128898873SFUJITA Tomonori 
46924bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
46930d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
46940d01c5dfSDouglas Gilbert 					    host_list) {
46950d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
46960d01c5dfSDouglas Gilbert 						    dev_list) {
46970d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
46980d01c5dfSDouglas Gilbert 						dp->uas_bm);
46990d01c5dfSDouglas Gilbert 				}
47000d01c5dfSDouglas Gilbert 			}
47014bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
47020d01c5dfSDouglas Gilbert 		}
4703c65b1445SDouglas Gilbert 		return count;
4704c65b1445SDouglas Gilbert 	}
4705c65b1445SDouglas Gilbert 	return -EINVAL;
4706c65b1445SDouglas Gilbert }
470782069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
4708c65b1445SDouglas Gilbert 
470982069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
47101da177e4SLinus Torvalds {
4711773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
47121da177e4SLinus Torvalds }
47131da177e4SLinus Torvalds 
4714fd32119bSDouglas Gilbert static int sdebug_add_adapter(void);
4715fd32119bSDouglas Gilbert static void sdebug_remove_adapter(void);
4716fd32119bSDouglas Gilbert 
471782069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
471882069379SAkinobu Mita 			      size_t count)
47191da177e4SLinus Torvalds {
47201da177e4SLinus Torvalds 	int delta_hosts;
47211da177e4SLinus Torvalds 
4722f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
47231da177e4SLinus Torvalds 		return -EINVAL;
47241da177e4SLinus Torvalds 	if (delta_hosts > 0) {
47251da177e4SLinus Torvalds 		do {
47261da177e4SLinus Torvalds 			sdebug_add_adapter();
47271da177e4SLinus Torvalds 		} while (--delta_hosts);
47281da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
47291da177e4SLinus Torvalds 		do {
47301da177e4SLinus Torvalds 			sdebug_remove_adapter();
47311da177e4SLinus Torvalds 		} while (++delta_hosts);
47321da177e4SLinus Torvalds 	}
47331da177e4SLinus Torvalds 	return count;
47341da177e4SLinus Torvalds }
473582069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
47361da177e4SLinus Torvalds 
473782069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
473823183910SDouglas Gilbert {
4739773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
474023183910SDouglas Gilbert }
474182069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
474282069379SAkinobu Mita 				    size_t count)
474323183910SDouglas Gilbert {
474423183910SDouglas Gilbert 	int n;
474523183910SDouglas Gilbert 
474623183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4747773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
474823183910SDouglas Gilbert 		return count;
474923183910SDouglas Gilbert 	}
475023183910SDouglas Gilbert 	return -EINVAL;
475123183910SDouglas Gilbert }
475282069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
475323183910SDouglas Gilbert 
4754c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
4755c4837394SDouglas Gilbert {
4756c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
4757c4837394SDouglas Gilbert }
4758c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
4759c4837394SDouglas Gilbert 				size_t count)
4760c4837394SDouglas Gilbert {
4761c4837394SDouglas Gilbert 	int n;
4762c4837394SDouglas Gilbert 
4763c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
4764c4837394SDouglas Gilbert 		if (n > 0)
4765c4837394SDouglas Gilbert 			sdebug_statistics = true;
4766c4837394SDouglas Gilbert 		else {
4767c4837394SDouglas Gilbert 			clear_queue_stats();
4768c4837394SDouglas Gilbert 			sdebug_statistics = false;
4769c4837394SDouglas Gilbert 		}
4770c4837394SDouglas Gilbert 		return count;
4771c4837394SDouglas Gilbert 	}
4772c4837394SDouglas Gilbert 	return -EINVAL;
4773c4837394SDouglas Gilbert }
4774c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
4775c4837394SDouglas Gilbert 
477682069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
4777597136abSMartin K. Petersen {
4778773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
4779597136abSMartin K. Petersen }
478082069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
4781597136abSMartin K. Petersen 
4782c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
4783c4837394SDouglas Gilbert {
4784c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
4785c4837394SDouglas Gilbert }
4786c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
4787c4837394SDouglas Gilbert 
478882069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
4789c6a44287SMartin K. Petersen {
4790773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
4791c6a44287SMartin K. Petersen }
479282069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
4793c6a44287SMartin K. Petersen 
479482069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
4795c6a44287SMartin K. Petersen {
4796773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
4797c6a44287SMartin K. Petersen }
479882069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
4799c6a44287SMartin K. Petersen 
480082069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
4801c6a44287SMartin K. Petersen {
4802773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
4803c6a44287SMartin K. Petersen }
480482069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
4805c6a44287SMartin K. Petersen 
480682069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
4807c6a44287SMartin K. Petersen {
4808773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
4809c6a44287SMartin K. Petersen }
481082069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
4811c6a44287SMartin K. Petersen 
481282069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
481344d92694SMartin K. Petersen {
481444d92694SMartin K. Petersen 	ssize_t count;
481544d92694SMartin K. Petersen 
48165b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
481744d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
481844d92694SMartin K. Petersen 				 sdebug_store_sectors);
481944d92694SMartin K. Petersen 
4820c7badc90STejun Heo 	count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
4821c7badc90STejun Heo 			  (int)map_size, map_storep);
482244d92694SMartin K. Petersen 	buf[count++] = '\n';
4823c7badc90STejun Heo 	buf[count] = '\0';
482444d92694SMartin K. Petersen 
482544d92694SMartin K. Petersen 	return count;
482644d92694SMartin K. Petersen }
482782069379SAkinobu Mita static DRIVER_ATTR_RO(map);
482844d92694SMartin K. Petersen 
482982069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
4830d986788bSMartin Pitt {
4831773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
4832d986788bSMartin Pitt }
483382069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
483482069379SAkinobu Mita 			       size_t count)
4835d986788bSMartin Pitt {
4836d986788bSMartin Pitt 	int n;
4837d986788bSMartin Pitt 
4838d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4839773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
4840d986788bSMartin Pitt 		return count;
4841d986788bSMartin Pitt 	}
4842d986788bSMartin Pitt 	return -EINVAL;
4843d986788bSMartin Pitt }
484482069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
4845d986788bSMartin Pitt 
4846cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4847cbf67842SDouglas Gilbert {
4848773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
4849cbf67842SDouglas Gilbert }
4850185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
4851cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4852cbf67842SDouglas Gilbert 			       size_t count)
4853cbf67842SDouglas Gilbert {
4854185dd232SDouglas Gilbert 	int n;
4855cbf67842SDouglas Gilbert 
4856cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4857185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
4858185dd232SDouglas Gilbert 		return count;
4859cbf67842SDouglas Gilbert 	}
4860cbf67842SDouglas Gilbert 	return -EINVAL;
4861cbf67842SDouglas Gilbert }
4862cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
4863cbf67842SDouglas Gilbert 
4864c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
4865c2248fc9SDouglas Gilbert {
4866773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
4867c2248fc9SDouglas Gilbert }
4868c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4869c2248fc9SDouglas Gilbert 			    size_t count)
4870c2248fc9SDouglas Gilbert {
4871c2248fc9SDouglas Gilbert 	int n;
4872c2248fc9SDouglas Gilbert 
4873c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4874773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
4875c2248fc9SDouglas Gilbert 		return count;
4876c2248fc9SDouglas Gilbert 	}
4877c2248fc9SDouglas Gilbert 	return -EINVAL;
4878c2248fc9SDouglas Gilbert }
4879c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
4880c2248fc9SDouglas Gilbert 
488109ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
488209ba24c1SDouglas Gilbert {
488309ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
488409ba24c1SDouglas Gilbert }
488509ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
488609ba24c1SDouglas Gilbert 
4887cbf67842SDouglas Gilbert 
488882069379SAkinobu Mita /* Note: The following array creates attribute files in the
488923183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
489023183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
489123183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
489223183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
489323183910SDouglas Gilbert  */
48946ecaff7fSRandy Dunlap 
489582069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
489682069379SAkinobu Mita 	&driver_attr_delay.attr,
489782069379SAkinobu Mita 	&driver_attr_opts.attr,
489882069379SAkinobu Mita 	&driver_attr_ptype.attr,
489982069379SAkinobu Mita 	&driver_attr_dsense.attr,
490082069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
490182069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
490282069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
490382069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
490482069379SAkinobu Mita 	&driver_attr_num_parts.attr,
490582069379SAkinobu Mita 	&driver_attr_every_nth.attr,
490682069379SAkinobu Mita 	&driver_attr_max_luns.attr,
490782069379SAkinobu Mita 	&driver_attr_max_queue.attr,
490882069379SAkinobu Mita 	&driver_attr_no_uld.attr,
490982069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
491082069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
491182069379SAkinobu Mita 	&driver_attr_add_host.attr,
491282069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
491382069379SAkinobu Mita 	&driver_attr_sector_size.attr,
4914c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
4915c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
491682069379SAkinobu Mita 	&driver_attr_dix.attr,
491782069379SAkinobu Mita 	&driver_attr_dif.attr,
491882069379SAkinobu Mita 	&driver_attr_guard.attr,
491982069379SAkinobu Mita 	&driver_attr_ato.attr,
492082069379SAkinobu Mita 	&driver_attr_map.attr,
492182069379SAkinobu Mita 	&driver_attr_removable.attr,
4922cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
4923cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
4924c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
492509ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
492682069379SAkinobu Mita 	NULL,
492782069379SAkinobu Mita };
492882069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
49291da177e4SLinus Torvalds 
493011ddcecaSAkinobu Mita static struct device *pseudo_primary;
49318dea0d02SFUJITA Tomonori 
49321da177e4SLinus Torvalds static int __init scsi_debug_init(void)
49331da177e4SLinus Torvalds {
49345f2578e5SFUJITA Tomonori 	unsigned long sz;
49351da177e4SLinus Torvalds 	int host_to_add;
49361da177e4SLinus Torvalds 	int k;
49376ecaff7fSRandy Dunlap 	int ret;
49381da177e4SLinus Torvalds 
4939cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
4940cbf67842SDouglas Gilbert 
4941773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
4942c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
4943773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
4944773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
4945c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
4946cbf67842SDouglas Gilbert 
4947773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
4948597136abSMartin K. Petersen 	case  512:
4949597136abSMartin K. Petersen 	case 1024:
4950597136abSMartin K. Petersen 	case 2048:
4951597136abSMartin K. Petersen 	case 4096:
4952597136abSMartin K. Petersen 		break;
4953597136abSMartin K. Petersen 	default:
4954773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
4955597136abSMartin K. Petersen 		return -EINVAL;
4956597136abSMartin K. Petersen 	}
4957597136abSMartin K. Petersen 
4958773642d9SDouglas Gilbert 	switch (sdebug_dif) {
49598475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
4960f46eb0e9SDouglas Gilbert 		break;
49618475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
49628475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
49638475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
4964f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
4965c6a44287SMartin K. Petersen 		break;
4966c6a44287SMartin K. Petersen 
4967c6a44287SMartin K. Petersen 	default:
4968c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
4969c6a44287SMartin K. Petersen 		return -EINVAL;
4970c6a44287SMartin K. Petersen 	}
4971c6a44287SMartin K. Petersen 
4972773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
4973c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
4974c6a44287SMartin K. Petersen 		return -EINVAL;
4975c6a44287SMartin K. Petersen 	}
4976c6a44287SMartin K. Petersen 
4977773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
4978c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
4979c6a44287SMartin K. Petersen 		return -EINVAL;
4980c6a44287SMartin K. Petersen 	}
4981c6a44287SMartin K. Petersen 
4982773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
4983773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
4984ea61fca5SMartin K. Petersen 		return -EINVAL;
4985ea61fca5SMartin K. Petersen 	}
49868d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
49878d039e22SDouglas Gilbert 		pr_warn("max_luns can be no more than 256, use default\n");
49888d039e22SDouglas Gilbert 		sdebug_max_luns = DEF_MAX_LUNS;
49898d039e22SDouglas Gilbert 	}
4990ea61fca5SMartin K. Petersen 
4991773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
4992773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
4993ea61fca5SMartin K. Petersen 		return -EINVAL;
4994ea61fca5SMartin K. Petersen 	}
4995ea61fca5SMartin K. Petersen 
4996c4837394SDouglas Gilbert 	if (submit_queues < 1) {
4997c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
4998c4837394SDouglas Gilbert 		return -EINVAL;
4999c4837394SDouglas Gilbert 	}
5000c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
5001c4837394SDouglas Gilbert 			       GFP_KERNEL);
5002c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
5003c4837394SDouglas Gilbert 		return -ENOMEM;
5004c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
5005c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
5006c4837394SDouglas Gilbert 
5007773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
5008773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
5009773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
5010773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
501128898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
50121da177e4SLinus Torvalds 
50131da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
50141da177e4SLinus Torvalds 	sdebug_heads = 8;
50151da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
5016773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
50171da177e4SLinus Torvalds 		sdebug_heads = 64;
5018773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
5019fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
50201da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
50211da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
50221da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
50231da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
50241da177e4SLinus Torvalds 		sdebug_heads = 255;
50251da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
50261da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
50271da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
50281da177e4SLinus Torvalds 	}
50291da177e4SLinus Torvalds 
5030b01f6f83SDouglas Gilbert 	if (sdebug_fake_rw == 0) {
50311da177e4SLinus Torvalds 		fake_storep = vmalloc(sz);
50321da177e4SLinus Torvalds 		if (NULL == fake_storep) {
5033c1287970STomas Winkler 			pr_err("out of memory, 1\n");
5034c4837394SDouglas Gilbert 			ret = -ENOMEM;
5035c4837394SDouglas Gilbert 			goto free_q_arr;
50361da177e4SLinus Torvalds 		}
50371da177e4SLinus Torvalds 		memset(fake_storep, 0, sz);
5038773642d9SDouglas Gilbert 		if (sdebug_num_parts > 0)
5039f58b0efbSFUJITA Tomonori 			sdebug_build_parts(fake_storep, sz);
5040cbf67842SDouglas Gilbert 	}
50411da177e4SLinus Torvalds 
5042773642d9SDouglas Gilbert 	if (sdebug_dix) {
5043c6a44287SMartin K. Petersen 		int dif_size;
5044c6a44287SMartin K. Petersen 
50456ebf105cSChristoph Hellwig 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
5046c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
5047c6a44287SMartin K. Petersen 
5048c1287970STomas Winkler 		pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
5049c6a44287SMartin K. Petersen 
5050c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
5051c1287970STomas Winkler 			pr_err("out of mem. (DIX)\n");
5052c6a44287SMartin K. Petersen 			ret = -ENOMEM;
5053c6a44287SMartin K. Petersen 			goto free_vm;
5054c6a44287SMartin K. Petersen 		}
5055c6a44287SMartin K. Petersen 
5056c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
5057c6a44287SMartin K. Petersen 	}
5058c6a44287SMartin K. Petersen 
50595b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
50605b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
5061773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
5062773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
50636014759cSMartin K. Petersen 
5064773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
5065773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
50666014759cSMartin K. Petersen 
5067773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
5068773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
50696014759cSMartin K. Petersen 
5070773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
5071773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
5072773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
5073c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
5074c4837394SDouglas Gilbert 			ret = -EINVAL;
5075c4837394SDouglas Gilbert 			goto free_vm;
507644d92694SMartin K. Petersen 		}
507744d92694SMartin K. Petersen 
5078b90ebc3dSAkinobu Mita 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
5079b90ebc3dSAkinobu Mita 		map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
508044d92694SMartin K. Petersen 
5081c1287970STomas Winkler 		pr_info("%lu provisioning blocks\n", map_size);
508244d92694SMartin K. Petersen 
508344d92694SMartin K. Petersen 		if (map_storep == NULL) {
5084c1287970STomas Winkler 			pr_err("out of mem. (MAP)\n");
508544d92694SMartin K. Petersen 			ret = -ENOMEM;
508644d92694SMartin K. Petersen 			goto free_vm;
508744d92694SMartin K. Petersen 		}
508844d92694SMartin K. Petersen 
5089b90ebc3dSAkinobu Mita 		bitmap_zero(map_storep, map_size);
509044d92694SMartin K. Petersen 
509144d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
5092773642d9SDouglas Gilbert 		if (sdebug_num_parts)
509344d92694SMartin K. Petersen 			map_region(0, 2);
509444d92694SMartin K. Petersen 	}
509544d92694SMartin K. Petersen 
50969b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
50979b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
5098c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
50999b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
51006ecaff7fSRandy Dunlap 		goto free_vm;
51016ecaff7fSRandy Dunlap 	}
51026ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
51036ecaff7fSRandy Dunlap 	if (ret < 0) {
5104c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
51056ecaff7fSRandy Dunlap 		goto dev_unreg;
51066ecaff7fSRandy Dunlap 	}
51076ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
51086ecaff7fSRandy Dunlap 	if (ret < 0) {
5109c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
51106ecaff7fSRandy Dunlap 		goto bus_unreg;
51116ecaff7fSRandy Dunlap 	}
51121da177e4SLinus Torvalds 
5113773642d9SDouglas Gilbert 	host_to_add = sdebug_add_host;
5114773642d9SDouglas Gilbert 	sdebug_add_host = 0;
51151da177e4SLinus Torvalds 
51161da177e4SLinus Torvalds         for (k = 0; k < host_to_add; k++) {
51171da177e4SLinus Torvalds                 if (sdebug_add_adapter()) {
5118c1287970STomas Winkler 			pr_err("sdebug_add_adapter failed k=%d\n", k);
51191da177e4SLinus Torvalds                         break;
51201da177e4SLinus Torvalds                 }
51211da177e4SLinus Torvalds         }
51221da177e4SLinus Torvalds 
5123773642d9SDouglas Gilbert 	if (sdebug_verbose)
5124773642d9SDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_add_host);
5125c1287970STomas Winkler 
51261da177e4SLinus Torvalds 	return 0;
51276ecaff7fSRandy Dunlap 
51286ecaff7fSRandy Dunlap bus_unreg:
51296ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
51306ecaff7fSRandy Dunlap dev_unreg:
51319b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
51326ecaff7fSRandy Dunlap free_vm:
513344d92694SMartin K. Petersen 	vfree(map_storep);
5134c6a44287SMartin K. Petersen 	vfree(dif_storep);
51356ecaff7fSRandy Dunlap 	vfree(fake_storep);
5136c4837394SDouglas Gilbert free_q_arr:
5137c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
51386ecaff7fSRandy Dunlap 	return ret;
51391da177e4SLinus Torvalds }
51401da177e4SLinus Torvalds 
51411da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
51421da177e4SLinus Torvalds {
5143773642d9SDouglas Gilbert 	int k = sdebug_add_host;
51441da177e4SLinus Torvalds 
51451da177e4SLinus Torvalds 	stop_all_queued();
5146cbf67842SDouglas Gilbert 	free_all_queued();
51471da177e4SLinus Torvalds 	for (; k; k--)
51481da177e4SLinus Torvalds 		sdebug_remove_adapter();
51491da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
51501da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
51519b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
51521da177e4SLinus Torvalds 
51534d2b496fSEwan D. Milne 	vfree(map_storep);
5154c6a44287SMartin K. Petersen 	vfree(dif_storep);
51551da177e4SLinus Torvalds 	vfree(fake_storep);
5156c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
51571da177e4SLinus Torvalds }
51581da177e4SLinus Torvalds 
51591da177e4SLinus Torvalds device_initcall(scsi_debug_init);
51601da177e4SLinus Torvalds module_exit(scsi_debug_exit);
51611da177e4SLinus Torvalds 
51621da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev)
51631da177e4SLinus Torvalds {
51641da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
51651da177e4SLinus Torvalds 
51661da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
51671da177e4SLinus Torvalds         kfree(sdbg_host);
51681da177e4SLinus Torvalds }
51691da177e4SLinus Torvalds 
51701da177e4SLinus Torvalds static int sdebug_add_adapter(void)
51711da177e4SLinus Torvalds {
51721da177e4SLinus Torvalds 	int k, devs_per_host;
51731da177e4SLinus Torvalds         int error = 0;
51741da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
51758b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
51761da177e4SLinus Torvalds 
517724669f75SJes Sorensen         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
51781da177e4SLinus Torvalds         if (NULL == sdbg_host) {
5179c1287970STomas Winkler 		pr_err("out of memory at line %d\n", __LINE__);
51801da177e4SLinus Torvalds                 return -ENOMEM;
51811da177e4SLinus Torvalds         }
51821da177e4SLinus Torvalds 
51831da177e4SLinus Torvalds         INIT_LIST_HEAD(&sdbg_host->dev_info_list);
51841da177e4SLinus Torvalds 
5185773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
51861da177e4SLinus Torvalds         for (k = 0; k < devs_per_host; k++) {
51875cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
51885cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
5189c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
51901da177e4SLinus Torvalds                         error = -ENOMEM;
51911da177e4SLinus Torvalds 			goto clean;
51921da177e4SLinus Torvalds                 }
51931da177e4SLinus Torvalds         }
51941da177e4SLinus Torvalds 
51951da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
51961da177e4SLinus Torvalds         list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
51971da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
51981da177e4SLinus Torvalds 
51991da177e4SLinus Torvalds         sdbg_host->dev.bus = &pseudo_lld_bus;
52009b906779SNicholas Bellinger         sdbg_host->dev.parent = pseudo_primary;
52011da177e4SLinus Torvalds         sdbg_host->dev.release = &sdebug_release_adapter;
5202773642d9SDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
52031da177e4SLinus Torvalds 
52041da177e4SLinus Torvalds         error = device_register(&sdbg_host->dev);
52051da177e4SLinus Torvalds 
52061da177e4SLinus Torvalds         if (error)
52071da177e4SLinus Torvalds 		goto clean;
52081da177e4SLinus Torvalds 
5209773642d9SDouglas Gilbert 	++sdebug_add_host;
52101da177e4SLinus Torvalds         return error;
52111da177e4SLinus Torvalds 
52121da177e4SLinus Torvalds clean:
52138b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
52148b40228fSFUJITA Tomonori 				 dev_list) {
52151da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
52161da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
52171da177e4SLinus Torvalds 	}
52181da177e4SLinus Torvalds 
52191da177e4SLinus Torvalds 	kfree(sdbg_host);
52201da177e4SLinus Torvalds         return error;
52211da177e4SLinus Torvalds }
52221da177e4SLinus Torvalds 
52231da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
52241da177e4SLinus Torvalds {
52251da177e4SLinus Torvalds         struct sdebug_host_info * sdbg_host = NULL;
52261da177e4SLinus Torvalds 
52271da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
52281da177e4SLinus Torvalds         if (!list_empty(&sdebug_host_list)) {
52291da177e4SLinus Torvalds                 sdbg_host = list_entry(sdebug_host_list.prev,
52301da177e4SLinus Torvalds                                        struct sdebug_host_info, host_list);
52311da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
52321da177e4SLinus Torvalds 	}
52331da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
52341da177e4SLinus Torvalds 
52351da177e4SLinus Torvalds 	if (!sdbg_host)
52361da177e4SLinus Torvalds 		return;
52371da177e4SLinus Torvalds 
52381da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
5239773642d9SDouglas Gilbert 	--sdebug_add_host;
52401da177e4SLinus Torvalds }
52411da177e4SLinus Torvalds 
5242fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
5243cbf67842SDouglas Gilbert {
5244cbf67842SDouglas Gilbert 	int num_in_q = 0;
5245cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5246cbf67842SDouglas Gilbert 
5247c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
5248cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
5249cbf67842SDouglas Gilbert 	if (NULL == devip) {
5250c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
5251cbf67842SDouglas Gilbert 		return	-ENODEV;
5252cbf67842SDouglas Gilbert 	}
5253cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5254c40ecc12SChristoph Hellwig 
5255cbf67842SDouglas Gilbert 	if (qdepth < 1)
5256cbf67842SDouglas Gilbert 		qdepth = 1;
5257c4837394SDouglas Gilbert 	/* allow to exceed max host qc_arr elements for testing */
5258c4837394SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE + 10)
5259c4837394SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE + 10;
5260db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
5261cbf67842SDouglas Gilbert 
5262773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
5263c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
5264c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
5265cbf67842SDouglas Gilbert 	}
5266c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
5267cbf67842SDouglas Gilbert 	return sdev->queue_depth;
5268cbf67842SDouglas Gilbert }
5269cbf67842SDouglas Gilbert 
5270c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
5271817fd66bSDouglas Gilbert {
5272c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
5273773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
5274773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
5275773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
5276c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
5277773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
5278817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
5279c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
5280817fd66bSDouglas Gilbert 	}
5281c4837394SDouglas Gilbert 	return false;
5282817fd66bSDouglas Gilbert }
5283817fd66bSDouglas Gilbert 
5284fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5285fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
5286c2248fc9SDouglas Gilbert {
5287c2248fc9SDouglas Gilbert 	u8 sdeb_i;
5288c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
5289c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
5290c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
5291c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
5292c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
5293c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5294c2248fc9SDouglas Gilbert 	int k, na;
5295c2248fc9SDouglas Gilbert 	int errsts = 0;
5296c2248fc9SDouglas Gilbert 	u32 flags;
5297c2248fc9SDouglas Gilbert 	u16 sa;
5298c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
5299c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
5300c2248fc9SDouglas Gilbert 
5301c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
5302c4837394SDouglas Gilbert 	if (sdebug_statistics)
5303c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
5304f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
5305f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
5306c2248fc9SDouglas Gilbert 		char b[120];
5307c2248fc9SDouglas Gilbert 		int n, len, sb;
5308c2248fc9SDouglas Gilbert 
5309c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
5310c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
5311c2248fc9SDouglas Gilbert 		if (len > 32)
5312c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
5313c2248fc9SDouglas Gilbert 		else {
5314c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
5315c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
5316c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
5317c2248fc9SDouglas Gilbert 		}
5318c4837394SDouglas Gilbert 		if (sdebug_mq_active)
5319c4837394SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n",
5320c4837394SDouglas Gilbert 				    my_name, blk_mq_unique_tag(scp->request),
5321c4837394SDouglas Gilbert 				    b);
5322c4837394SDouglas Gilbert 		else
5323c4837394SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name,
5324c4837394SDouglas Gilbert 				    b);
5325c2248fc9SDouglas Gilbert 	}
532634d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
5327f46eb0e9SDouglas Gilbert 	if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5328f46eb0e9SDouglas Gilbert 		goto err_out;
5329c2248fc9SDouglas Gilbert 
5330c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
5331c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
5332c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
5333f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
5334f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5335c2248fc9SDouglas Gilbert 		if (NULL == devip)
5336f46eb0e9SDouglas Gilbert 			goto err_out;
5337c2248fc9SDouglas Gilbert 	}
5338c2248fc9SDouglas Gilbert 	na = oip->num_attached;
5339c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
5340c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
5341c2248fc9SDouglas Gilbert 		r_oip = oip;
5342c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
5343c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
5344c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
5345c2248fc9SDouglas Gilbert 			else
5346c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
5347c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5348c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
5349c2248fc9SDouglas Gilbert 					break;
5350c2248fc9SDouglas Gilbert 			}
5351c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
5352c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5353c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
5354c2248fc9SDouglas Gilbert 					break;
5355c2248fc9SDouglas Gilbert 			}
5356c2248fc9SDouglas Gilbert 		}
5357c2248fc9SDouglas Gilbert 		if (k > na) {
5358c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
5359c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5360c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
5361c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5362c2248fc9SDouglas Gilbert 			else
5363c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
5364c2248fc9SDouglas Gilbert 			goto check_cond;
5365c2248fc9SDouglas Gilbert 		}
5366c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
5367c2248fc9SDouglas Gilbert 	flags = oip->flags;
5368f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
5369c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5370c2248fc9SDouglas Gilbert 		goto check_cond;
5371c2248fc9SDouglas Gilbert 	}
5372f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
5373773642d9SDouglas Gilbert 		if (sdebug_verbose)
5374773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5375773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
5376c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5377c2248fc9SDouglas Gilbert 		goto check_cond;
5378c2248fc9SDouglas Gilbert 	}
5379f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
5380c2248fc9SDouglas Gilbert 		u8 rem;
5381c2248fc9SDouglas Gilbert 		int j;
5382c2248fc9SDouglas Gilbert 
5383c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5384c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
5385c2248fc9SDouglas Gilbert 			if (rem) {
5386c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
5387c2248fc9SDouglas Gilbert 					if (0x80 & rem)
5388c2248fc9SDouglas Gilbert 						break;
5389c2248fc9SDouglas Gilbert 				}
5390c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5391c2248fc9SDouglas Gilbert 				goto check_cond;
5392c2248fc9SDouglas Gilbert 			}
5393c2248fc9SDouglas Gilbert 		}
5394c2248fc9SDouglas Gilbert 	}
5395f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
5396b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
5397b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
5398f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
5399c2248fc9SDouglas Gilbert 		if (errsts)
5400c2248fc9SDouglas Gilbert 			goto check_cond;
5401c2248fc9SDouglas Gilbert 	}
5402c4837394SDouglas Gilbert 	if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
5403c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
5404773642d9SDouglas Gilbert 		if (sdebug_verbose)
5405c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5406c2248fc9SDouglas Gilbert 				    "%s\n", my_name, "initializing command "
5407c2248fc9SDouglas Gilbert 				    "required");
5408c2248fc9SDouglas Gilbert 		errsts = check_condition_result;
5409c2248fc9SDouglas Gilbert 		goto fini;
5410c2248fc9SDouglas Gilbert 	}
5411773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
5412c2248fc9SDouglas Gilbert 		goto fini;
5413f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
5414c4837394SDouglas Gilbert 		if (fake_timeout(scp))
5415c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
5416c2248fc9SDouglas Gilbert 	}
5417f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
5418f46eb0e9SDouglas Gilbert 		errsts = oip->pfp(scp, devip);	/* calls a resp_* function */
5419c2248fc9SDouglas Gilbert 	else if (r_pfp)	/* if leaf function ptr NULL, try the root's */
5420c2248fc9SDouglas Gilbert 		errsts = r_pfp(scp, devip);
5421c2248fc9SDouglas Gilbert 
5422c2248fc9SDouglas Gilbert fini:
5423c2248fc9SDouglas Gilbert 	return schedule_resp(scp, devip, errsts,
5424c2206098SDouglas Gilbert 			     ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay));
5425c2248fc9SDouglas Gilbert check_cond:
5426c2248fc9SDouglas Gilbert 	return schedule_resp(scp, devip, check_condition_result, 0);
5427f46eb0e9SDouglas Gilbert err_out:
5428f46eb0e9SDouglas Gilbert 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0);
5429c2248fc9SDouglas Gilbert }
5430c2248fc9SDouglas Gilbert 
54319e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
5432c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
5433c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
54349e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
54359e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
54369e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
54379e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
54389e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
54399e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
54409e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
5441185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
5442cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
54439e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
54449e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
5445cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
5446cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
54479e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
5448c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
54499e603ca0SFUJITA Tomonori 	.this_id =		7,
545065e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
5451cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
54526bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
54539e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
54549e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
5455c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
54569e603ca0SFUJITA Tomonori };
54579e603ca0SFUJITA Tomonori 
54581da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev)
54591da177e4SLinus Torvalds {
54601da177e4SLinus Torvalds 	int error = 0;
54611da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
54621da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
5463f46eb0e9SDouglas Gilbert 	int hprot;
54641da177e4SLinus Torvalds 
54651da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
54661da177e4SLinus Torvalds 
5467773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
5468773642d9SDouglas Gilbert 	if (sdebug_clustering)
54690759c666SAkinobu Mita 		sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
54701da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
54711da177e4SLinus Torvalds 	if (NULL == hpnt) {
5472c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
54731da177e4SLinus Torvalds 		error = -ENODEV;
54741da177e4SLinus Torvalds 		return error;
54751da177e4SLinus Torvalds 	}
5476c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
54779b130ad5SAlexey Dobriyan 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
5478c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
5479c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
5480c4837394SDouglas Gilbert 	}
5481c4837394SDouglas Gilbert 	/* Decide whether to tell scsi subsystem that we want mq */
5482c4837394SDouglas Gilbert 	/* Following should give the same answer for each host */
5483c4837394SDouglas Gilbert 	sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1);
5484c4837394SDouglas Gilbert 	if (sdebug_mq_active)
5485c4837394SDouglas Gilbert 		hpnt->nr_hw_queues = submit_queues;
54861da177e4SLinus Torvalds 
54871da177e4SLinus Torvalds         sdbg_host->shost = hpnt;
54881da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
5489773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5490773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
54911da177e4SLinus Torvalds 	else
5492773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
5493773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
5494f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
54951da177e4SLinus Torvalds 
5496f46eb0e9SDouglas Gilbert 	hprot = 0;
5497c6a44287SMartin K. Petersen 
5498773642d9SDouglas Gilbert 	switch (sdebug_dif) {
5499c6a44287SMartin K. Petersen 
55008475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
5501f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
5502773642d9SDouglas Gilbert 		if (sdebug_dix)
5503f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
5504c6a44287SMartin K. Petersen 		break;
5505c6a44287SMartin K. Petersen 
55068475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
5507f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
5508773642d9SDouglas Gilbert 		if (sdebug_dix)
5509f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
5510c6a44287SMartin K. Petersen 		break;
5511c6a44287SMartin K. Petersen 
55128475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
5513f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
5514773642d9SDouglas Gilbert 		if (sdebug_dix)
5515f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
5516c6a44287SMartin K. Petersen 		break;
5517c6a44287SMartin K. Petersen 
5518c6a44287SMartin K. Petersen 	default:
5519773642d9SDouglas Gilbert 		if (sdebug_dix)
5520f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
5521c6a44287SMartin K. Petersen 		break;
5522c6a44287SMartin K. Petersen 	}
5523c6a44287SMartin K. Petersen 
5524f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
5525c6a44287SMartin K. Petersen 
5526f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
5527c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
5528f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5529f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5530f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5531f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5532f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5533f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5534f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
5535c6a44287SMartin K. Petersen 
5536773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
5537c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5538c6a44287SMartin K. Petersen 	else
5539c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5540c6a44287SMartin K. Petersen 
5541773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5542773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
5543c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
5544c4837394SDouglas Gilbert 		sdebug_statistics = true;
55451da177e4SLinus Torvalds         error = scsi_add_host(hpnt, &sdbg_host->dev);
55461da177e4SLinus Torvalds         if (error) {
5547c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
55481da177e4SLinus Torvalds                 error = -ENODEV;
55491da177e4SLinus Torvalds 		scsi_host_put(hpnt);
55501da177e4SLinus Torvalds         } else
55511da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
55521da177e4SLinus Torvalds 
55531da177e4SLinus Torvalds 	return error;
55541da177e4SLinus Torvalds }
55551da177e4SLinus Torvalds 
55561da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev)
55571da177e4SLinus Torvalds {
55581da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
55598b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
55601da177e4SLinus Torvalds 
55611da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
55621da177e4SLinus Torvalds 
55631da177e4SLinus Torvalds 	if (!sdbg_host) {
5564c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
55651da177e4SLinus Torvalds 		return -ENODEV;
55661da177e4SLinus Torvalds 	}
55671da177e4SLinus Torvalds 
55681da177e4SLinus Torvalds         scsi_remove_host(sdbg_host->shost);
55691da177e4SLinus Torvalds 
55708b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
55718b40228fSFUJITA Tomonori 				 dev_list) {
55721da177e4SLinus Torvalds                 list_del(&sdbg_devinfo->dev_list);
55731da177e4SLinus Torvalds                 kfree(sdbg_devinfo);
55741da177e4SLinus Torvalds         }
55751da177e4SLinus Torvalds 
55761da177e4SLinus Torvalds         scsi_host_put(sdbg_host->shost);
55771da177e4SLinus Torvalds         return 0;
55781da177e4SLinus Torvalds }
55791da177e4SLinus Torvalds 
55808dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
55818dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
55821da177e4SLinus Torvalds {
55838dea0d02SFUJITA Tomonori 	return 1;
55848dea0d02SFUJITA Tomonori }
55851da177e4SLinus Torvalds 
55868dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
55878dea0d02SFUJITA Tomonori 	.name = "pseudo",
55888dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
55898dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
55908dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
559182069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
55928dea0d02SFUJITA Tomonori };
5593