xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 8b0e1953)
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
128b01f6f83SDouglas Gilbert #define DEF_PTYPE   TYPE_DISK
129d986788bSMartin Pitt #define DEF_REMOVABLE false
130760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
1315b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1325b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1335b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1346014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1356014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1365b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1375b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1385b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
139c2248fc9SDouglas Gilbert #define DEF_STRICT 0
140c4837394SDouglas Gilbert #define DEF_STATISTICS false
141c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1
14209ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0
143c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999
1441da177e4SLinus Torvalds 
145b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0
146b01f6f83SDouglas Gilbert 
147773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
148773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
149773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
150773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
151773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
152773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
153773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
154773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
155773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
156773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
157773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
158773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF		0x400
159773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF		0x800
160773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE		0x1000
161773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE		0x2000
162773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE		0x4000
163773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
164773642d9SDouglas Gilbert 			      SDEBUG_OPT_RESET_NOISE)
165773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
166773642d9SDouglas Gilbert 				  SDEBUG_OPT_TRANSPORT_ERR | \
167773642d9SDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
168773642d9SDouglas Gilbert 				  SDEBUG_OPT_SHORT_TRANSFER)
1691da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
170fd32119bSDouglas Gilbert  *   - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
1711da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
172773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_RECOVERED_ERR is set.
1736f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
174773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_TRANSPORT_ERR is set.
1751da177e4SLinus Torvalds  *
1761da177e4SLinus Torvalds  * When "every_nth" < 0 then after "- every_nth" commands:
177fd32119bSDouglas Gilbert  *   - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
1781da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
179773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_RECOVERED_ERR is set.
1806f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
181773642d9SDouglas Gilbert  *     commands if _DEBUG_OPT_TRANSPORT_ERR is set.
182773642d9SDouglas Gilbert  * This will continue on every subsequent command until some other action
183773642d9SDouglas Gilbert  * occurs (e.g. the user * writing a new value (other than -1 or 1) to
184773642d9SDouglas Gilbert  * every_nth via sysfs).
1851da177e4SLinus Torvalds  */
1861da177e4SLinus Torvalds 
187cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
188cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
189cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
190cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
191cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
192cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1
193cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2
1940d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3
19519c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4
196acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5	/* simulate firmware change */
197acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
198acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7
199cbf67842SDouglas Gilbert 
200773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
2011da177e4SLinus Torvalds  * sector on read commands: */
2021da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
20332f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2041da177e4SLinus Torvalds 
2051da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
2061da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
2071da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
2081da177e4SLinus Torvalds 
209c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
210c4837394SDouglas Gilbert  * (for response) per submit queue at one time. Can be reduced by max_queue
211c4837394SDouglas Gilbert  * option. Command responses are not queued when jdelay=0 and ndelay=0. The
212c4837394SDouglas Gilbert  * per-device DEF_CMD_PER_LUN can be changed via sysfs:
213c4837394SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
214c4837394SDouglas Gilbert  * but cannot exceed SDEBUG_CANQUEUE .
215c4837394SDouglas Gilbert  */
216c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS  3	/* a WORD is bits in a long */
217c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE  (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
218cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN  255
219cbf67842SDouglas Gilbert 
220fd32119bSDouglas Gilbert #define F_D_IN			1
221fd32119bSDouglas Gilbert #define F_D_OUT			2
222fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
223fd32119bSDouglas Gilbert #define F_D_UNKN		8
224fd32119bSDouglas Gilbert #define F_RL_WLUN_OK		0x10
225fd32119bSDouglas Gilbert #define F_SKIP_UA		0x20
226fd32119bSDouglas Gilbert #define F_DELAY_OVERR		0x40
227fd32119bSDouglas Gilbert #define F_SA_LOW		0x80	/* cdb byte 1, bits 4 to 0 */
228fd32119bSDouglas Gilbert #define F_SA_HIGH		0x100	/* as used by variable length cdbs */
229fd32119bSDouglas Gilbert #define F_INV_OP		0x200
230fd32119bSDouglas Gilbert #define F_FAKE_RW		0x400
231fd32119bSDouglas Gilbert #define F_M_ACCESS		0x800	/* media access */
232fd32119bSDouglas Gilbert 
233fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
234fd32119bSDouglas Gilbert #define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW)
235fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
236fd32119bSDouglas Gilbert 
237fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4
238fd32119bSDouglas Gilbert 
239b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32
240fd32119bSDouglas Gilbert 
241fd32119bSDouglas Gilbert 
242fd32119bSDouglas Gilbert struct sdebug_dev_info {
243fd32119bSDouglas Gilbert 	struct list_head dev_list;
244fd32119bSDouglas Gilbert 	unsigned int channel;
245fd32119bSDouglas Gilbert 	unsigned int target;
246fd32119bSDouglas Gilbert 	u64 lun;
24709ba24c1SDouglas Gilbert 	uuid_be lu_name;
248fd32119bSDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
249fd32119bSDouglas Gilbert 	unsigned long uas_bm[1];
250fd32119bSDouglas Gilbert 	atomic_t num_in_q;
251c4837394SDouglas Gilbert 	atomic_t stopped;
252fd32119bSDouglas Gilbert 	bool used;
253fd32119bSDouglas Gilbert };
254fd32119bSDouglas Gilbert 
255fd32119bSDouglas Gilbert struct sdebug_host_info {
256fd32119bSDouglas Gilbert 	struct list_head host_list;
257fd32119bSDouglas Gilbert 	struct Scsi_Host *shost;
258fd32119bSDouglas Gilbert 	struct device dev;
259fd32119bSDouglas Gilbert 	struct list_head dev_info_list;
260fd32119bSDouglas Gilbert };
261fd32119bSDouglas Gilbert 
262fd32119bSDouglas Gilbert #define to_sdebug_host(d)	\
263fd32119bSDouglas Gilbert 	container_of(d, struct sdebug_host_info, dev)
264fd32119bSDouglas Gilbert 
265fd32119bSDouglas Gilbert struct sdebug_defer {
266fd32119bSDouglas Gilbert 	struct hrtimer hrt;
267fd32119bSDouglas Gilbert 	struct execute_work ew;
268c4837394SDouglas Gilbert 	int sqa_idx;	/* index of sdebug_queue array */
269c4837394SDouglas Gilbert 	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
270c4837394SDouglas Gilbert 	int issuing_cpu;
271fd32119bSDouglas Gilbert };
272fd32119bSDouglas Gilbert 
273fd32119bSDouglas Gilbert struct sdebug_queued_cmd {
274c4837394SDouglas Gilbert 	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
275c4837394SDouglas Gilbert 	 * instance indicates this slot is in use.
276c4837394SDouglas Gilbert 	 */
277fd32119bSDouglas Gilbert 	struct sdebug_defer *sd_dp;
278fd32119bSDouglas Gilbert 	struct scsi_cmnd *a_cmnd;
279c4837394SDouglas Gilbert 	unsigned int inj_recovered:1;
280c4837394SDouglas Gilbert 	unsigned int inj_transport:1;
281c4837394SDouglas Gilbert 	unsigned int inj_dif:1;
282c4837394SDouglas Gilbert 	unsigned int inj_dix:1;
283c4837394SDouglas Gilbert 	unsigned int inj_short:1;
284fd32119bSDouglas Gilbert };
285fd32119bSDouglas Gilbert 
286c4837394SDouglas Gilbert struct sdebug_queue {
287c4837394SDouglas Gilbert 	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
288c4837394SDouglas Gilbert 	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
289c4837394SDouglas Gilbert 	spinlock_t qc_lock;
290c4837394SDouglas Gilbert 	atomic_t blocked;	/* to temporarily stop more being queued */
291fd32119bSDouglas Gilbert };
292fd32119bSDouglas Gilbert 
293c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count;   /* number of incoming commands */
294c4837394SDouglas Gilbert static atomic_t sdebug_completions;  /* count of deferred completions */
295c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
296c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
297c4837394SDouglas Gilbert 
298fd32119bSDouglas Gilbert struct opcode_info_t {
299b01f6f83SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
300b01f6f83SDouglas Gilbert 				/* for terminating element */
301fd32119bSDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
302fd32119bSDouglas Gilbert 	u16 sa;			/* service action */
303fd32119bSDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
304fd32119bSDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
305fd32119bSDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
306fd32119bSDouglas Gilbert 	u8 len_mask[16];	/* len=len_mask[0], then mask for cdb[1]... */
307fd32119bSDouglas Gilbert 				/* ignore cdb bytes after position 15 */
308fd32119bSDouglas Gilbert };
309fd32119bSDouglas Gilbert 
310fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
311c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
312c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
313c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
314c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
315c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
316c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
317c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
318c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
319c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
320c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
321c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
322c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
323c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
324c2248fc9SDouglas Gilbert 	SDEB_I_SERV_ACT_IN = 12,	/* 12, 16 */
325c2248fc9SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT = 13,	/* 12, 16 */
326c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
327c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
328c2248fc9SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* 10 only */
329c2248fc9SDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,
330c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
331c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
332c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
333c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
334c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
335c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
336c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
337c2248fc9SDouglas Gilbert 	SDEB_I_XDWRITEREAD = 25,	/* 10 only */
338c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_BUFFER = 26,
339c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_SAME = 27,		/* 10, 16 */
340c2248fc9SDouglas Gilbert 	SDEB_I_SYNC_CACHE = 28,		/* 10 only */
341c2248fc9SDouglas Gilbert 	SDEB_I_COMP_WRITE = 29,
342c2248fc9SDouglas Gilbert 	SDEB_I_LAST_ELEMENT = 30,	/* keep this last */
343c2248fc9SDouglas Gilbert };
344c2248fc9SDouglas Gilbert 
345c4837394SDouglas Gilbert 
346c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
347c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
348c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
349c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
350c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
351c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
352c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
353c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
354c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
355c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
356c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
357c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
358c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
359c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
360c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
361c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
362c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
363c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
364c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
365c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
366fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
367c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
368c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
369c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
370c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
371c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
372c2248fc9SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
373c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
374c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT,
375c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
376c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
377c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
378c2248fc9SDouglas Gilbert 	SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN,
379c2248fc9SDouglas Gilbert 	     0, 0, 0, 0,
380c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
381c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
382c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
383c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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 };
388c2248fc9SDouglas Gilbert 
389c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
390c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
391c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
392c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
393c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
394c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
395c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
396c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
397c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
398c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
399c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
400c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
401c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
402c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
40338d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
40438d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
405c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
406c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
407c2248fc9SDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
40838d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
409acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
410c2248fc9SDouglas Gilbert 
411c2248fc9SDouglas Gilbert static const struct opcode_info_t msense_iarr[1] = {
412c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
413c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
414c2248fc9SDouglas Gilbert };
415c2248fc9SDouglas Gilbert 
416c2248fc9SDouglas Gilbert static const struct opcode_info_t mselect_iarr[1] = {
417c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
418c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
419c2248fc9SDouglas Gilbert };
420c2248fc9SDouglas Gilbert 
421c2248fc9SDouglas Gilbert static const struct opcode_info_t read_iarr[3] = {
422c2248fc9SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */
423c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
424c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
425c2248fc9SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */
426c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
427c2248fc9SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */
428c2248fc9SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
429c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
430c2248fc9SDouglas Gilbert };
431c2248fc9SDouglas Gilbert 
432c2248fc9SDouglas Gilbert static const struct opcode_info_t write_iarr[3] = {
433c2248fc9SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,   /* 10 */
434c2248fc9SDouglas Gilbert 	    {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
435c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
436c2248fc9SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,    /* 6 */
437c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
438c2248fc9SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,   /* 12 */
439c2248fc9SDouglas Gilbert 	    {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
440c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
441c2248fc9SDouglas Gilbert };
442c2248fc9SDouglas Gilbert 
443c2248fc9SDouglas Gilbert static const struct opcode_info_t sa_in_iarr[1] = {
444c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
445c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
446c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },
447c2248fc9SDouglas Gilbert };
448c2248fc9SDouglas Gilbert 
449c2248fc9SDouglas Gilbert static const struct opcode_info_t vl_iarr[1] = {	/* VARIABLE LENGTH */
450c2248fc9SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0,
451c2248fc9SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa,
452c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
453c2248fc9SDouglas Gilbert };
454c2248fc9SDouglas Gilbert 
455c2248fc9SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[2] = {
45638d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
457c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
458c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
45938d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
460c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
461c2248fc9SDouglas Gilbert 	     0, 0} },
462c2248fc9SDouglas Gilbert };
463c2248fc9SDouglas Gilbert 
464c2248fc9SDouglas Gilbert static const struct opcode_info_t write_same_iarr[1] = {
465c2248fc9SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL,
466c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
467c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x1f, 0xc7} },
468c2248fc9SDouglas Gilbert };
469c2248fc9SDouglas Gilbert 
470c2248fc9SDouglas Gilbert static const struct opcode_info_t reserve_iarr[1] = {
471c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,	/* RESERVE(6) */
472c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
473c2248fc9SDouglas Gilbert };
474c2248fc9SDouglas Gilbert 
475c2248fc9SDouglas Gilbert static const struct opcode_info_t release_iarr[1] = {
476c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,	/* RELEASE(6) */
477c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
478c2248fc9SDouglas Gilbert };
479c2248fc9SDouglas Gilbert 
480c2248fc9SDouglas Gilbert 
481c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
482c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
483c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
484c2248fc9SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
485c2248fc9SDouglas Gilbert /* 0 */
486c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,
487c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
488c2248fc9SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL,
489c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
490c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
491c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
492c2248fc9SDouglas Gilbert 	     0, 0} },
493c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
494c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
495c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
496c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
497c2248fc9SDouglas Gilbert 	{1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr,
498c2248fc9SDouglas Gilbert 	    {10,  0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
499c2248fc9SDouglas Gilbert 	     0} },
500c2248fc9SDouglas Gilbert 	{1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr,
501c2248fc9SDouglas Gilbert 	    {10,  0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
502c2248fc9SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,
503c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
504c2248fc9SDouglas Gilbert 	     0, 0, 0} },
505c2248fc9SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,
506c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
507c2248fc9SDouglas Gilbert 	     0, 0} },
508c2248fc9SDouglas Gilbert 	{3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr,
509c2248fc9SDouglas Gilbert 	    {16,  0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
510c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x9f, 0xc7} },		/* READ(16) */
511c2248fc9SDouglas Gilbert /* 10 */
512c2248fc9SDouglas Gilbert 	{3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr,
513c2248fc9SDouglas Gilbert 	    {16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
514c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x9f, 0xc7} },		/* WRITE(16) */
515c2248fc9SDouglas Gilbert 	{0, 0x1b, 0, 0, resp_start_stop, NULL,		/* START STOP UNIT */
516c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
517c2248fc9SDouglas Gilbert 	{1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr,
518c2248fc9SDouglas Gilbert 	    {16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
519c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x1, 0xc7} },	/* READ CAPACITY(16) */
520c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */
521c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
522c2248fc9SDouglas Gilbert 	{2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr,
523c2248fc9SDouglas Gilbert 	    {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0,
524c2248fc9SDouglas Gilbert 	     0} },
525c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
526c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
527f7f9f26bSDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */
528f7f9f26bSDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
529f7f9f26bSDouglas Gilbert 	     0, 0, 0, 0, 0, 0} },
530c2248fc9SDouglas Gilbert 	{1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0,
531c2248fc9SDouglas Gilbert 	    vl_iarr, {32,  0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0,
532c2248fc9SDouglas Gilbert 		      0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */
533c2248fc9SDouglas Gilbert 	{1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */
534c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
535c2248fc9SDouglas Gilbert 	     0} },
536c2248fc9SDouglas Gilbert 	{1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */
537c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
538c2248fc9SDouglas Gilbert 	     0} },
539c2248fc9SDouglas Gilbert /* 20 */
540f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
541f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
542c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
543c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
544c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
545c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
546c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
547c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
548c2248fc9SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */
549c2248fc9SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
550c2248fc9SDouglas Gilbert 	{0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10,
551c2248fc9SDouglas Gilbert 	    NULL, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7,
552c2248fc9SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
553acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
554acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
555acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
556c2248fc9SDouglas Gilbert 	{1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10,
557c2248fc9SDouglas Gilbert 	    write_same_iarr, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff,
558c2248fc9SDouglas Gilbert 			      0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
559c2248fc9SDouglas Gilbert 	{0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */
560c2248fc9SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
561c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
56238d5c833SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL,
563c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
564c2248fc9SDouglas Gilbert 	     0, 0xff, 0x1f, 0xc7} },		/* COMPARE AND WRITE */
565c2248fc9SDouglas Gilbert 
566c2248fc9SDouglas Gilbert /* 30 */
567c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
568c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
569c2248fc9SDouglas Gilbert };
570c2248fc9SDouglas Gilbert 
571773642d9SDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;
572773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
573c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
574773642d9SDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
575773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
576773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
577773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
578773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
579773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
580773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
581773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
582773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
583c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
584cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
585c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
586773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
587773642d9SDouglas Gilbert static int sdebug_no_uld;
588773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
589773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
590773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
591773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
592773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
593b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
594773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
595773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
596773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
597773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
598773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
599773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
600773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
601773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
602773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
603773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
604773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
605773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
606773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
60709ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL;
608773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
609773642d9SDouglas Gilbert static bool sdebug_clustering;
610773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
611773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
612817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
613773642d9SDouglas Gilbert static bool sdebug_verbose;
614f46eb0e9SDouglas Gilbert static bool have_dif_prot;
615c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS;
616c4837394SDouglas Gilbert static bool sdebug_mq_active;
6171da177e4SLinus Torvalds 
618c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
6191da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
6201da177e4SLinus Torvalds 
6211da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
6221da177e4SLinus Torvalds    may still need them */
6231da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
6241da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
6251da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
6261da177e4SLinus Torvalds 
6271da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
6281da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
6291da177e4SLinus Torvalds 
6301da177e4SLinus Torvalds static unsigned char *fake_storep;	/* ramdisk storage */
6316ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_storep;	/* protection info */
63244d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
6331da177e4SLinus Torvalds 
63444d92694SMartin K. Petersen static unsigned long map_size;
635cbf67842SDouglas Gilbert static int num_aborts;
636cbf67842SDouglas Gilbert static int num_dev_resets;
637cbf67842SDouglas Gilbert static int num_target_resets;
638cbf67842SDouglas Gilbert static int num_bus_resets;
639cbf67842SDouglas Gilbert static int num_host_resets;
640c6a44287SMartin K. Petersen static int dix_writes;
641c6a44287SMartin K. Petersen static int dix_reads;
642c6a44287SMartin K. Petersen static int dif_errors;
6431da177e4SLinus Torvalds 
644c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
645c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
646fd32119bSDouglas Gilbert 
6471da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
6481da177e4SLinus Torvalds 
649cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
650cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
6511da177e4SLinus Torvalds 
6521da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
6531da177e4SLinus Torvalds 
6541da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
6551da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
6561da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
6571da177e4SLinus Torvalds };
6581da177e4SLinus Torvalds 
6591da177e4SLinus Torvalds static const int check_condition_result =
6601da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
6611da177e4SLinus Torvalds 
662c6a44287SMartin K. Petersen static const int illegal_condition_result =
663c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
664c6a44287SMartin K. Petersen 
665cbf67842SDouglas Gilbert static const int device_qfull_result =
666cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
667cbf67842SDouglas Gilbert 
668fd32119bSDouglas Gilbert 
669760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or
670760f3b03SDouglas Gilbert  * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
671760f3b03SDouglas Gilbert  * real reads and writes (i.e. not skipping them for speed).
672760f3b03SDouglas Gilbert  */
673760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void)
674fd32119bSDouglas Gilbert {
675fd32119bSDouglas Gilbert 	return 0 == sdebug_fake_rw &&
676fd32119bSDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
677fd32119bSDouglas Gilbert }
678c65b1445SDouglas Gilbert 
67914faa944SAkinobu Mita static void *fake_store(unsigned long long lba)
68014faa944SAkinobu Mita {
68114faa944SAkinobu Mita 	lba = do_div(lba, sdebug_store_sectors);
68214faa944SAkinobu Mita 
683773642d9SDouglas Gilbert 	return fake_storep + lba * sdebug_sector_size;
68414faa944SAkinobu Mita }
68514faa944SAkinobu Mita 
6866ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_store(sector_t sector)
68714faa944SAkinobu Mita {
68849413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
68914faa944SAkinobu Mita 
69014faa944SAkinobu Mita 	return dif_storep + sector;
69114faa944SAkinobu Mita }
69214faa944SAkinobu Mita 
6938dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
6948dea0d02SFUJITA Tomonori {
6958dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
6968dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
6978dea0d02SFUJITA Tomonori 
6988dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
6998dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
7008dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
7018dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
702773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
703773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
7048dea0d02SFUJITA Tomonori 		else
705773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
706773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
707f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
7088dea0d02SFUJITA Tomonori 	}
7098dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
7108dea0d02SFUJITA Tomonori }
7118dea0d02SFUJITA Tomonori 
71222017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
71322017ed2SDouglas Gilbert 
71422017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
715fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
716fd32119bSDouglas Gilbert 				 enum sdeb_cmd_data c_d,
71722017ed2SDouglas Gilbert 				 int in_byte, int in_bit)
71822017ed2SDouglas Gilbert {
71922017ed2SDouglas Gilbert 	unsigned char *sbuff;
72022017ed2SDouglas Gilbert 	u8 sks[4];
72122017ed2SDouglas Gilbert 	int sl, asc;
72222017ed2SDouglas Gilbert 
72322017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
72422017ed2SDouglas Gilbert 	if (!sbuff) {
72522017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
72622017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
72722017ed2SDouglas Gilbert 		return;
72822017ed2SDouglas Gilbert 	}
72922017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
73022017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
731773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
73222017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
73322017ed2SDouglas Gilbert 	sks[0] = 0x80;
73422017ed2SDouglas Gilbert 	if (c_d)
73522017ed2SDouglas Gilbert 		sks[0] |= 0x40;
73622017ed2SDouglas Gilbert 	if (in_bit >= 0) {
73722017ed2SDouglas Gilbert 		sks[0] |= 0x8;
73822017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
73922017ed2SDouglas Gilbert 	}
74022017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
741773642d9SDouglas Gilbert 	if (sdebug_dsense) {
74222017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
74322017ed2SDouglas Gilbert 		sbuff[7] = sl;
74422017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
74522017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
74622017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
74722017ed2SDouglas Gilbert 	} else
74822017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
749773642d9SDouglas Gilbert 	if (sdebug_verbose)
75022017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
75122017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
75222017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
75322017ed2SDouglas Gilbert }
75422017ed2SDouglas Gilbert 
755cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
7568dea0d02SFUJITA Tomonori {
7578dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
7588dea0d02SFUJITA Tomonori 
759cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
760cbf67842SDouglas Gilbert 	if (!sbuff) {
761cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
762cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
763cbf67842SDouglas Gilbert 		return;
764cbf67842SDouglas Gilbert 	}
765cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
7668dea0d02SFUJITA Tomonori 
767773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
7688dea0d02SFUJITA Tomonori 
769773642d9SDouglas Gilbert 	if (sdebug_verbose)
770cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
771cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
772cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
7738dea0d02SFUJITA Tomonori }
7741da177e4SLinus Torvalds 
775fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
77622017ed2SDouglas Gilbert {
77722017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
77822017ed2SDouglas Gilbert }
77922017ed2SDouglas Gilbert 
7801da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
7811da177e4SLinus Torvalds {
782773642d9SDouglas Gilbert 	if (sdebug_verbose) {
783cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
784cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
785cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
786cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
787cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
788cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
789cbf67842SDouglas Gilbert 				    __func__);
790cbf67842SDouglas Gilbert 		else
791cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
792cbf67842SDouglas Gilbert 				    __func__, cmd);
7931da177e4SLinus Torvalds 	}
7941da177e4SLinus Torvalds 	return -EINVAL;
7951da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
7961da177e4SLinus Torvalds }
7971da177e4SLinus Torvalds 
79819c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
79919c8ead7SEwan D. Milne {
80019c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
80119c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
80219c8ead7SEwan D. Milne 
80319c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
80419c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
80519c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
80619c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
80719c8ead7SEwan D. Milne 			    (devip->target == dp->target))
80819c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
80919c8ead7SEwan D. Milne 		}
81019c8ead7SEwan D. Milne 	}
81119c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
81219c8ead7SEwan D. Milne }
81319c8ead7SEwan D. Milne 
814f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
8151da177e4SLinus Torvalds {
816cbf67842SDouglas Gilbert 	int k;
817cbf67842SDouglas Gilbert 
818cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
819cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
820cbf67842SDouglas Gilbert 		const char *cp = NULL;
821cbf67842SDouglas Gilbert 
822cbf67842SDouglas Gilbert 		switch (k) {
823cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
824f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
825f46eb0e9SDouglas Gilbert 					POWER_ON_RESET_ASCQ);
826773642d9SDouglas Gilbert 			if (sdebug_verbose)
827cbf67842SDouglas Gilbert 				cp = "power on reset";
828cbf67842SDouglas Gilbert 			break;
829cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
830f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
831f46eb0e9SDouglas Gilbert 					BUS_RESET_ASCQ);
832773642d9SDouglas Gilbert 			if (sdebug_verbose)
833cbf67842SDouglas Gilbert 				cp = "bus reset";
834cbf67842SDouglas Gilbert 			break;
835cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
836f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
837f46eb0e9SDouglas Gilbert 					MODE_CHANGED_ASCQ);
838773642d9SDouglas Gilbert 			if (sdebug_verbose)
839cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
840cbf67842SDouglas Gilbert 			break;
8410d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
842f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
843f46eb0e9SDouglas Gilbert 					CAPACITY_CHANGED_ASCQ);
844773642d9SDouglas Gilbert 			if (sdebug_verbose)
8450d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
846f49accf1SEwan D. Milne 			break;
847acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
848f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
849b01f6f83SDouglas Gilbert 					TARGET_CHANGED_ASC,
850b01f6f83SDouglas Gilbert 					MICROCODE_CHANGED_ASCQ);
851773642d9SDouglas Gilbert 			if (sdebug_verbose)
852acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
853acafd0b9SEwan D. Milne 			break;
854acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
855f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
856acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
857acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
858773642d9SDouglas Gilbert 			if (sdebug_verbose)
859acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
860acafd0b9SEwan D. Milne 			break;
86119c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
86219c8ead7SEwan D. Milne 			/*
86319c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
86419c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
86519c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
86619c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
867773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
86819c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
86919c8ead7SEwan D. Milne 			 */
870773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
87119c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
872f46eb0e9SDouglas Gilbert 			mk_sense_buffer(scp, UNIT_ATTENTION,
87319c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
87419c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
875773642d9SDouglas Gilbert 			if (sdebug_verbose)
87619c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
87719c8ead7SEwan D. Milne 			break;
878cbf67842SDouglas Gilbert 		default:
879773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
880773642d9SDouglas Gilbert 			if (sdebug_verbose)
881cbf67842SDouglas Gilbert 				cp = "unknown";
882cbf67842SDouglas Gilbert 			break;
883cbf67842SDouglas Gilbert 		}
884cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
885773642d9SDouglas Gilbert 		if (sdebug_verbose)
886f46eb0e9SDouglas Gilbert 			sdev_printk(KERN_INFO, scp->device,
887cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
888cbf67842SDouglas Gilbert 				   my_name, cp);
8891da177e4SLinus Torvalds 		return check_condition_result;
8901da177e4SLinus Torvalds 	}
8911da177e4SLinus Torvalds 	return 0;
8921da177e4SLinus Torvalds }
8931da177e4SLinus Torvalds 
894fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
8951da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
8961da177e4SLinus Torvalds 				int arr_len)
8971da177e4SLinus Torvalds {
89821a61829SFUJITA Tomonori 	int act_len;
899072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
9001da177e4SLinus Torvalds 
901072d0bb3SFUJITA Tomonori 	if (!sdb->length)
9021da177e4SLinus Torvalds 		return 0;
903072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
904773642d9SDouglas Gilbert 		return DID_ERROR << 16;
90521a61829SFUJITA Tomonori 
90621a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
90721a61829SFUJITA Tomonori 				      arr, arr_len);
90821a61829SFUJITA Tomonori 	sdb->resid = scsi_bufflen(scp) - act_len;
90921a61829SFUJITA Tomonori 
9101da177e4SLinus Torvalds 	return 0;
9111da177e4SLinus Torvalds }
9121da177e4SLinus Torvalds 
913fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
914fb0cc8d1SDouglas Gilbert  * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
915fb0cc8d1SDouglas Gilbert  * calls, not required to write in ascending offset order. Assumes resid
916fb0cc8d1SDouglas Gilbert  * set to scsi_bufflen() prior to any calls.
917fb0cc8d1SDouglas Gilbert  */
918fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
919fb0cc8d1SDouglas Gilbert 				  int arr_len, unsigned int off_dst)
920fb0cc8d1SDouglas Gilbert {
921fb0cc8d1SDouglas Gilbert 	int act_len, n;
922fb0cc8d1SDouglas Gilbert 	struct scsi_data_buffer *sdb = scsi_in(scp);
923fb0cc8d1SDouglas Gilbert 	off_t skip = off_dst;
924fb0cc8d1SDouglas Gilbert 
925fb0cc8d1SDouglas Gilbert 	if (sdb->length <= off_dst)
926fb0cc8d1SDouglas Gilbert 		return 0;
927fb0cc8d1SDouglas Gilbert 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
928fb0cc8d1SDouglas Gilbert 		return DID_ERROR << 16;
929fb0cc8d1SDouglas Gilbert 
930fb0cc8d1SDouglas Gilbert 	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
931fb0cc8d1SDouglas Gilbert 				       arr, arr_len, skip);
932fb0cc8d1SDouglas Gilbert 	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
933fb0cc8d1SDouglas Gilbert 		 __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid);
934fb0cc8d1SDouglas Gilbert 	n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
935fb0cc8d1SDouglas Gilbert 	sdb->resid = min(sdb->resid, n);
936fb0cc8d1SDouglas Gilbert 	return 0;
937fb0cc8d1SDouglas Gilbert }
938fb0cc8d1SDouglas Gilbert 
939fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
940fb0cc8d1SDouglas Gilbert  * 'arr' or -1 if error.
941fb0cc8d1SDouglas Gilbert  */
9421da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
94321a61829SFUJITA Tomonori 			       int arr_len)
9441da177e4SLinus Torvalds {
94521a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
9461da177e4SLinus Torvalds 		return 0;
947072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
9481da177e4SLinus Torvalds 		return -1;
94921a61829SFUJITA Tomonori 
95021a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
9511da177e4SLinus Torvalds }
9521da177e4SLinus Torvalds 
9531da177e4SLinus Torvalds 
9541da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux   ";
9551da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug      ";
956773642d9SDouglas Gilbert static const char *inq_product_rev = "0186";	/* version less '.' */
9571b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */
9581b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL;
9591b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL;
9601b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL;
9611da177e4SLinus Torvalds 
962cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
963760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
9645a09e398SHannes Reinecke 			  int target_dev_id, int dev_id_num,
96509ba24c1SDouglas Gilbert 			  const char *dev_id_str, int dev_id_str_len,
96609ba24c1SDouglas Gilbert 			  const uuid_be *lu_name)
9671da177e4SLinus Torvalds {
968c65b1445SDouglas Gilbert 	int num, port_a;
969c65b1445SDouglas Gilbert 	char b[32];
9701da177e4SLinus Torvalds 
971c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
9721da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
9731da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
9741da177e4SLinus Torvalds 	arr[1] = 0x1;
9751da177e4SLinus Torvalds 	arr[2] = 0x0;
9761da177e4SLinus Torvalds 	memcpy(&arr[4], inq_vendor_id, 8);
9771da177e4SLinus Torvalds 	memcpy(&arr[12], inq_product_id, 16);
9781da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
9791da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
9801da177e4SLinus Torvalds 	arr[3] = num;
9811da177e4SLinus Torvalds 	num += 4;
982c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
98309ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl) {
98409ba24c1SDouglas Gilbert 			/* Locally assigned UUID */
98509ba24c1SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
98609ba24c1SDouglas Gilbert 			arr[num++] = 0xa;  /* PIV=0, lu, naa */
98709ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
98809ba24c1SDouglas Gilbert 			arr[num++] = 0x12;
98909ba24c1SDouglas Gilbert 			arr[num++] = 0x10; /* uuid type=1, locally assigned */
99009ba24c1SDouglas Gilbert 			arr[num++] = 0x0;
99109ba24c1SDouglas Gilbert 			memcpy(arr + num, lu_name, 16);
99209ba24c1SDouglas Gilbert 			num += 16;
99309ba24c1SDouglas Gilbert 		} else {
9941b37bd60SDouglas Gilbert 			/* NAA-3, Logical unit identifier (binary) */
995c65b1445SDouglas Gilbert 			arr[num++] = 0x1;  /* binary (not necessarily sas) */
996c65b1445SDouglas Gilbert 			arr[num++] = 0x3;  /* PIV=0, lu, naa */
997c65b1445SDouglas Gilbert 			arr[num++] = 0x0;
998c65b1445SDouglas Gilbert 			arr[num++] = 0x8;
9991b37bd60SDouglas Gilbert 			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
1000773642d9SDouglas Gilbert 			num += 8;
100109ba24c1SDouglas Gilbert 		}
1002c65b1445SDouglas Gilbert 		/* Target relative port number */
1003c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
1004c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
1005c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1006c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
1007c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1008c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
1009c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
1010c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
1011c65b1445SDouglas Gilbert 	}
10121b37bd60SDouglas Gilbert 	/* NAA-3, Target port identifier */
1013c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1014c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
1015c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1016c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
10171b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1018773642d9SDouglas Gilbert 	num += 8;
10191b37bd60SDouglas Gilbert 	/* NAA-3, Target port group identifier */
10205a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
10215a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
10225a09e398SHannes Reinecke 	arr[num++] = 0x0;
10235a09e398SHannes Reinecke 	arr[num++] = 0x4;
10245a09e398SHannes Reinecke 	arr[num++] = 0;
10255a09e398SHannes Reinecke 	arr[num++] = 0;
1026773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
1027773642d9SDouglas Gilbert 	num += 2;
10281b37bd60SDouglas Gilbert 	/* NAA-3, Target device identifier */
1029c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1030c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1031c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1032c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
10331b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
1034773642d9SDouglas Gilbert 	num += 8;
1035c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1036c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1037c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1038c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1039c65b1445SDouglas Gilbert 	arr[num++] = 24;
10401b37bd60SDouglas Gilbert 	memcpy(arr + num, "naa.32222220", 12);
1041c65b1445SDouglas Gilbert 	num += 12;
1042c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1043c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1044c65b1445SDouglas Gilbert 	num += 8;
1045c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1046c65b1445SDouglas Gilbert 	num += 4;
1047c65b1445SDouglas Gilbert 	return num;
1048c65b1445SDouglas Gilbert }
1049c65b1445SDouglas Gilbert 
1050c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1051c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1052c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1053c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1054c65b1445SDouglas Gilbert };
1055c65b1445SDouglas Gilbert 
1056cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1057760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr)
1058c65b1445SDouglas Gilbert {
1059c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1060c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1061c65b1445SDouglas Gilbert }
1062c65b1445SDouglas Gilbert 
1063cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1064760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr)
1065c65b1445SDouglas Gilbert {
1066c65b1445SDouglas Gilbert 	int num = 0;
1067c65b1445SDouglas Gilbert 	const char * na1 = "https://www.kernel.org/config";
1068c65b1445SDouglas Gilbert 	const char * na2 = "http://www.kernel.org/log";
1069c65b1445SDouglas Gilbert 	int plen, olen;
1070c65b1445SDouglas Gilbert 
1071c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1072c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1073c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1074c65b1445SDouglas Gilbert 	olen = strlen(na1);
1075c65b1445SDouglas Gilbert 	plen = olen + 1;
1076c65b1445SDouglas Gilbert 	if (plen % 4)
1077c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1078c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1079c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1080c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1081c65b1445SDouglas Gilbert 	num += plen;
1082c65b1445SDouglas Gilbert 
1083c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1084c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1085c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1086c65b1445SDouglas Gilbert 	olen = strlen(na2);
1087c65b1445SDouglas Gilbert 	plen = olen + 1;
1088c65b1445SDouglas Gilbert 	if (plen % 4)
1089c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1090c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1091c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1092c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1093c65b1445SDouglas Gilbert 	num += plen;
1094c65b1445SDouglas Gilbert 
1095c65b1445SDouglas Gilbert 	return num;
1096c65b1445SDouglas Gilbert }
1097c65b1445SDouglas Gilbert 
1098c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1099760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
1100c65b1445SDouglas Gilbert {
1101c65b1445SDouglas Gilbert 	int num = 0;
1102c65b1445SDouglas Gilbert 	int port_a, port_b;
1103c65b1445SDouglas Gilbert 
1104c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1105c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1106c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1107c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1108c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1109c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1110c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1111c65b1445SDouglas Gilbert 	num += 6;
1112c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1113c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1114c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1115c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1116c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1117c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1118c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
11191b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
1120773642d9SDouglas Gilbert 	num += 8;
1121c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1122c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1123c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1124c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1125c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1126c65b1445SDouglas Gilbert 	num += 6;
1127c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1128c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1129c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1130c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1131c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1132c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1133c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
11341b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
1135773642d9SDouglas Gilbert 	num += 8;
1136c65b1445SDouglas Gilbert 
1137c65b1445SDouglas Gilbert 	return num;
1138c65b1445SDouglas Gilbert }
1139c65b1445SDouglas Gilbert 
1140c65b1445SDouglas Gilbert 
1141c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1142c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1143c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1144c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1145c65b1445SDouglas Gilbert '1','2','3','4',
1146c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1147c65b1445SDouglas Gilbert 0xec,0,0,0,
1148c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1149c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1150c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1151c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1152c65b1445SDouglas Gilbert 0x53,0x41,
1153c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1154c65b1445SDouglas Gilbert 0x20,0x20,
1155c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1156c65b1445SDouglas Gilbert 0x10,0x80,
1157c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1158c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1159c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1160c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1161c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1162c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1163c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1164c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1165c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1166c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1167c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1168c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1169c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1170c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1171c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1172c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0xa5,0x51,
1183c65b1445SDouglas Gilbert };
1184c65b1445SDouglas Gilbert 
1185cbf67842SDouglas Gilbert /* ATA Information VPD page */
1186760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr)
1187c65b1445SDouglas Gilbert {
1188c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1189c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1190c65b1445SDouglas Gilbert }
1191c65b1445SDouglas Gilbert 
1192c65b1445SDouglas Gilbert 
1193c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
11941e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
11951e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11961e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11971e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1198c65b1445SDouglas Gilbert };
1199c65b1445SDouglas Gilbert 
1200cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1201760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr)
1202c65b1445SDouglas Gilbert {
1203ea61fca5SMartin K. Petersen 	unsigned int gran;
1204ea61fca5SMartin K. Petersen 
1205c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1206e308b3d1SMartin K. Petersen 
1207e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
1208773642d9SDouglas Gilbert 	gran = 1 << sdebug_physblk_exp;
1209773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1210e308b3d1SMartin K. Petersen 
1211e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1212773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1213773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
121444d92694SMartin K. Petersen 
1215e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1216773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1217e308b3d1SMartin K. Petersen 
1218773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1219e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1220773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1221e308b3d1SMartin K. Petersen 
1222e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1223773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
122444d92694SMartin K. Petersen 	}
122544d92694SMartin K. Petersen 
1226e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1227773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1228773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
122944d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
123044d92694SMartin K. Petersen 	}
123144d92694SMartin K. Petersen 
1232e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1233773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
12346014759cSMartin K. Petersen 
12355b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1236773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
12375b94e232SMartin K. Petersen 
12385b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
123944d92694SMartin K. Petersen 
1240c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
12411da177e4SLinus Torvalds }
12421da177e4SLinus Torvalds 
12431e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
1244760f3b03SDouglas Gilbert static int inquiry_vpd_b1(unsigned char *arr)
1245eac6e8e4SMatthew Wilcox {
1246eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1247eac6e8e4SMatthew Wilcox 	arr[0] = 0;
12481e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
12491e49f785SDouglas Gilbert 	arr[2] = 0;
12501e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
1251eac6e8e4SMatthew Wilcox 
1252eac6e8e4SMatthew Wilcox 	return 0x3c;
1253eac6e8e4SMatthew Wilcox }
12541da177e4SLinus Torvalds 
1255760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */
1256760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr)
12576014759cSMartin K. Petersen {
12583f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
12596014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
1260773642d9SDouglas Gilbert 	if (sdebug_lbpu)
12616014759cSMartin K. Petersen 		arr[1] = 1 << 7;
1262773642d9SDouglas Gilbert 	if (sdebug_lbpws)
12636014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
1264773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
12655b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
1266760f3b03SDouglas Gilbert 	if (sdebug_lbprz && scsi_debug_lbp())
1267760f3b03SDouglas Gilbert 		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
1268760f3b03SDouglas Gilbert 	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
1269760f3b03SDouglas Gilbert 	/* minimum_percentage=0; provisioning_type=0 (unknown) */
1270760f3b03SDouglas Gilbert 	/* threshold_percentage=0 */
12713f0bc3b3SMartin K. Petersen 	return 0x4;
12726014759cSMartin K. Petersen }
12736014759cSMartin K. Petersen 
12741da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1275c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
12761da177e4SLinus Torvalds 
1277c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
12781da177e4SLinus Torvalds {
12791da177e4SLinus Torvalds 	unsigned char pq_pdt;
12805a09e398SHannes Reinecke 	unsigned char * arr;
128101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
12825a09e398SHannes Reinecke 	int alloc_len, n, ret;
1283760f3b03SDouglas Gilbert 	bool have_wlun, is_disk;
12841da177e4SLinus Torvalds 
1285773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
12866f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
12876f3cbf55SDouglas Gilbert 	if (! arr)
12886f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1289760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
1290b01f6f83SDouglas Gilbert 	have_wlun = scsi_is_wlun(scp->device->lun);
1291c2248fc9SDouglas Gilbert 	if (have_wlun)
1292b01f6f83SDouglas Gilbert 		pq_pdt = TYPE_WLUN;	/* present, wlun */
1293b01f6f83SDouglas Gilbert 	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1294b01f6f83SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
1295c65b1445SDouglas Gilbert 	else
1296773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
12971da177e4SLinus Torvalds 	arr[0] = pq_pdt;
12981da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
129922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
13005a09e398SHannes Reinecke 		kfree(arr);
13011da177e4SLinus Torvalds 		return check_condition_result;
13021da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
13035a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1304c65b1445SDouglas Gilbert 		char lu_id_str[6];
1305c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
13061da177e4SLinus Torvalds 
13075a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
13085a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1309b01f6f83SDouglas Gilbert 		if (sdebug_vpd_use_hostno == 0)
131023183910SDouglas Gilbert 			host_no = 0;
1311c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1312c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1313c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1314c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1315c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
13161da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1317c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1318c65b1445SDouglas Gilbert 			n = 4;
1319c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1320c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1321c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1322c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1323c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1324c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1325c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1326c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1327760f3b03SDouglas Gilbert 			if (is_disk) {	  /* SBC only */
1328c65b1445SDouglas Gilbert 				arr[n++] = 0x89;  /* ATA information */
1329760f3b03SDouglas Gilbert 				arr[n++] = 0xb0;  /* Block limits */
1330760f3b03SDouglas Gilbert 				arr[n++] = 0xb1;  /* Block characteristics */
1331760f3b03SDouglas Gilbert 				arr[n++] = 0xb2;  /* Logical Block Prov */
1332760f3b03SDouglas Gilbert 			}
1333c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
13341da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1335c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
13361da177e4SLinus Torvalds 			arr[3] = len;
1337c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
13381da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1339c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1340760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
13415a09e398SHannes Reinecke 						target_dev_id, lu_id_num,
134209ba24c1SDouglas Gilbert 						lu_id_str, len,
134309ba24c1SDouglas Gilbert 						&devip->lu_name);
1344c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1345c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1346760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_84(&arr[4]);
1347c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1348c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1349760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_85(&arr[4]);
1350c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1351c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1352c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
13538475c811SChristoph Hellwig 			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
1354c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1355760f3b03SDouglas Gilbert 			else if (have_dif_prot)
1356c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1357c6a44287SMartin K. Petersen 			else
1358c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1359c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1360c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1361c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1362c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1363c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1364c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1365c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1366c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1367c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1368c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1369760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1370760f3b03SDouglas Gilbert 		} else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
1371c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1372760f3b03SDouglas Gilbert 			n = inquiry_vpd_89(&arr[4]);
1373773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1374760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
1375c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1376760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b0(&arr[4]);
1377760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
1378eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
1379760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b1(&arr[4]);
1380760f3b03SDouglas Gilbert 		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
13816014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
1382760f3b03SDouglas Gilbert 			arr[3] = inquiry_vpd_b2(&arr[4]);
13831da177e4SLinus Torvalds 		} else {
138422017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
13855a09e398SHannes Reinecke 			kfree(arr);
13861da177e4SLinus Torvalds 			return check_condition_result;
13871da177e4SLinus Torvalds 		}
1388773642d9SDouglas Gilbert 		len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
13895a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1390c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
13915a09e398SHannes Reinecke 		kfree(arr);
13925a09e398SHannes Reinecke 		return ret;
13931da177e4SLinus Torvalds 	}
13941da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1395773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1396773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
13971da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
13981da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1399f46eb0e9SDouglas Gilbert 	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
1400b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0)
14015a09e398SHannes Reinecke 		arr[5] = 0x10; /* claim: implicit TGPS */
1402c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
14031da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1404c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
14051da177e4SLinus Torvalds 	memcpy(&arr[8], inq_vendor_id, 8);
14061da177e4SLinus Torvalds 	memcpy(&arr[16], inq_product_id, 16);
14071da177e4SLinus Torvalds 	memcpy(&arr[32], inq_product_rev, 4);
14081da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1409760f3b03SDouglas Gilbert 	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
1410760f3b03SDouglas Gilbert 	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
1411c65b1445SDouglas Gilbert 	n = 62;
1412760f3b03SDouglas Gilbert 	if (is_disk) {		/* SBC-4 no version claimed */
1413760f3b03SDouglas Gilbert 		put_unaligned_be16(0x600, arr + n);
1414760f3b03SDouglas Gilbert 		n += 2;
1415760f3b03SDouglas Gilbert 	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
1416760f3b03SDouglas Gilbert 		put_unaligned_be16(0x525, arr + n);
1417760f3b03SDouglas Gilbert 		n += 2;
14181da177e4SLinus Torvalds 	}
1419760f3b03SDouglas Gilbert 	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
14205a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
14211da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
14225a09e398SHannes Reinecke 	kfree(arr);
14235a09e398SHannes Reinecke 	return ret;
14241da177e4SLinus Torvalds }
14251da177e4SLinus Torvalds 
1426fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1427fd32119bSDouglas Gilbert 				   0, 0, 0x0, 0x0};
1428fd32119bSDouglas Gilbert 
14291da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp,
14301da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip)
14311da177e4SLinus Torvalds {
14321da177e4SLinus Torvalds 	unsigned char * sbuff;
143301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1434cbf67842SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
14352492fc09STomas Winkler 	bool dsense;
14361da177e4SLinus Torvalds 	int len = 18;
14371da177e4SLinus Torvalds 
1438c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1439c2248fc9SDouglas Gilbert 	dsense = !!(cmd[1] & 1);
1440cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
1441c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1442c2248fc9SDouglas Gilbert 		if (dsense) {
1443c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1444c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1445c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
1446c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
1447c2248fc9SDouglas Gilbert 			len = 8;
1448c65b1445SDouglas Gilbert 		} else {
1449c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1450c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1451c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1452c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
1453c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
1454c65b1445SDouglas Gilbert 		}
1455c65b1445SDouglas Gilbert 	} else {
1456cbf67842SDouglas Gilbert 		memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
1457773642d9SDouglas Gilbert 		if (arr[0] >= 0x70 && dsense == sdebug_dsense)
1458c2248fc9SDouglas Gilbert 			;	/* have sense and formats match */
1459c2248fc9SDouglas Gilbert 		else if (arr[0] <= 0x70) {
1460c2248fc9SDouglas Gilbert 			if (dsense) {
1461c2248fc9SDouglas Gilbert 				memset(arr, 0, 8);
1462c2248fc9SDouglas Gilbert 				arr[0] = 0x72;
1463c2248fc9SDouglas Gilbert 				len = 8;
1464c2248fc9SDouglas Gilbert 			} else {
1465c2248fc9SDouglas Gilbert 				memset(arr, 0, 18);
1466c2248fc9SDouglas Gilbert 				arr[0] = 0x70;
1467c2248fc9SDouglas Gilbert 				arr[7] = 0xa;
1468c2248fc9SDouglas Gilbert 			}
1469c2248fc9SDouglas Gilbert 		} else if (dsense) {
1470c2248fc9SDouglas Gilbert 			memset(arr, 0, 8);
14711da177e4SLinus Torvalds 			arr[0] = 0x72;
14721da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
14731da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
14741da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
14751da177e4SLinus Torvalds 			len = 8;
1476c2248fc9SDouglas Gilbert 		} else {
1477c2248fc9SDouglas Gilbert 			memset(arr, 0, 18);
1478c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1479c2248fc9SDouglas Gilbert 			arr[2] = sbuff[1];
1480c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1481c2248fc9SDouglas Gilbert 			arr[12] = sbuff[1];
1482c2248fc9SDouglas Gilbert 			arr[13] = sbuff[3];
1483c65b1445SDouglas Gilbert 		}
1484c2248fc9SDouglas Gilbert 
1485c65b1445SDouglas Gilbert 	}
1486cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
14871da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
14881da177e4SLinus Torvalds }
14891da177e4SLinus Torvalds 
1490c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp,
1491c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
1492c65b1445SDouglas Gilbert {
149301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1494c4837394SDouglas Gilbert 	int power_cond, stop;
1495c65b1445SDouglas Gilbert 
1496c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1497c65b1445SDouglas Gilbert 	if (power_cond) {
149822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1499c65b1445SDouglas Gilbert 		return check_condition_result;
1500c65b1445SDouglas Gilbert 	}
1501c4837394SDouglas Gilbert 	stop = !(cmd[4] & 1);
1502c4837394SDouglas Gilbert 	atomic_xchg(&devip->stopped, stop);
1503c65b1445SDouglas Gilbert 	return 0;
1504c65b1445SDouglas Gilbert }
1505c65b1445SDouglas Gilbert 
150628898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
150728898873SFUJITA Tomonori {
1508773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1509773642d9SDouglas Gilbert 
1510773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1511773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1512773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
151328898873SFUJITA Tomonori 	else
151428898873SFUJITA Tomonori 		return sdebug_store_sectors;
151528898873SFUJITA Tomonori }
151628898873SFUJITA Tomonori 
15171da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
15181da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp,
15191da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
15201da177e4SLinus Torvalds {
15211da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1522c65b1445SDouglas Gilbert 	unsigned int capac;
15231da177e4SLinus Torvalds 
1524c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
152528898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
15261da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1527c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1528c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1529773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1530773642d9SDouglas Gilbert 	} else
1531773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1532773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
15331da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
15341da177e4SLinus Torvalds }
15351da177e4SLinus Torvalds 
1536c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1537c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp,
1538c65b1445SDouglas Gilbert 			  struct sdebug_dev_info * devip)
1539c65b1445SDouglas Gilbert {
154001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1541c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1542773642d9SDouglas Gilbert 	int alloc_len;
1543c65b1445SDouglas Gilbert 
1544773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1545c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
154628898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1547c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1548773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1549773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1550773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1551773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
155244d92694SMartin K. Petersen 
1553be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
15545b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1555760f3b03SDouglas Gilbert 		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1556760f3b03SDouglas Gilbert 		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1557760f3b03SDouglas Gilbert 		 * in the wider field maps to 0 in this field.
1558760f3b03SDouglas Gilbert 		 */
1559760f3b03SDouglas Gilbert 		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
1560760f3b03SDouglas Gilbert 			arr[14] |= 0x40;
1561be1dd78dSEric Sandeen 	}
156244d92694SMartin K. Petersen 
1563773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1564c6a44287SMartin K. Petersen 
1565760f3b03SDouglas Gilbert 	if (have_dif_prot) {
1566773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1567c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1568c6a44287SMartin K. Petersen 	}
1569c6a44287SMartin K. Petersen 
1570c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1571c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1572c65b1445SDouglas Gilbert }
1573c65b1445SDouglas Gilbert 
15745a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
15755a09e398SHannes Reinecke 
15765a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp,
15775a09e398SHannes Reinecke 			      struct sdebug_dev_info * devip)
15785a09e398SHannes Reinecke {
157901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
15805a09e398SHannes Reinecke 	unsigned char * arr;
15815a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
15825a09e398SHannes Reinecke 	int n, ret, alen, rlen;
15835a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
15845a09e398SHannes Reinecke 
1585773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
15866f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
15876f3cbf55SDouglas Gilbert 	if (! arr)
15886f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
15895a09e398SHannes Reinecke 	/*
15905a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
15915a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
15925a09e398SHannes Reinecke 	 * So we create two port groups with one port each
15935a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
15945a09e398SHannes Reinecke 	 */
15955a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
15965a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
15975a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
15985a09e398SHannes Reinecke 			(devip->channel & 0x7f);
15995a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
16005a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
16015a09e398SHannes Reinecke 
16025a09e398SHannes Reinecke 	/*
16035a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
16045a09e398SHannes Reinecke 	 */
16055a09e398SHannes Reinecke 	n = 4;
1606b01f6f83SDouglas Gilbert 	if (sdebug_vpd_use_hostno == 0) {
16075a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
16085a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
16095a09e398SHannes Reinecke 	} else {
16105a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1611773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
16125a09e398SHannes Reinecke 	}
1613773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1614773642d9SDouglas Gilbert 	n += 2;
16155a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
16165a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
16175a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
16185a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
16195a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
16205a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1621773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1622773642d9SDouglas Gilbert 	n += 2;
16235a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
16245a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1625773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1626773642d9SDouglas Gilbert 	n += 2;
16275a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
16285a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
16295a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
16305a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
16315a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
16325a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1633773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1634773642d9SDouglas Gilbert 	n += 2;
16355a09e398SHannes Reinecke 
16365a09e398SHannes Reinecke 	rlen = n - 4;
1637773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
16385a09e398SHannes Reinecke 
16395a09e398SHannes Reinecke 	/*
16405a09e398SHannes Reinecke 	 * Return the smallest value of either
16415a09e398SHannes Reinecke 	 * - The allocated length
16425a09e398SHannes Reinecke 	 * - The constructed command length
16435a09e398SHannes Reinecke 	 * - The maximum array size
16445a09e398SHannes Reinecke 	 */
16455a09e398SHannes Reinecke 	rlen = min(alen,n);
16465a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
16475a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
16485a09e398SHannes Reinecke 	kfree(arr);
16495a09e398SHannes Reinecke 	return ret;
16505a09e398SHannes Reinecke }
16515a09e398SHannes Reinecke 
1652fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1653fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
165438d5c833SDouglas Gilbert {
165538d5c833SDouglas Gilbert 	bool rctd;
165638d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
165738d5c833SDouglas Gilbert 	u16 req_sa, u;
165838d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
165938d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
166038d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
166138d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
166238d5c833SDouglas Gilbert 	u8 *arr;
166338d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
166438d5c833SDouglas Gilbert 
166538d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
166638d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
166738d5c833SDouglas Gilbert 	req_opcode = cmd[3];
166838d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
166938d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
16706d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
167138d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
167238d5c833SDouglas Gilbert 		return check_condition_result;
167338d5c833SDouglas Gilbert 	}
167438d5c833SDouglas Gilbert 	if (alloc_len > 8192)
167538d5c833SDouglas Gilbert 		a_len = 8192;
167638d5c833SDouglas Gilbert 	else
167738d5c833SDouglas Gilbert 		a_len = alloc_len;
167899531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
167938d5c833SDouglas Gilbert 	if (NULL == arr) {
168038d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
168138d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
168238d5c833SDouglas Gilbert 		return check_condition_result;
168338d5c833SDouglas Gilbert 	}
168438d5c833SDouglas Gilbert 	switch (reporting_opts) {
168538d5c833SDouglas Gilbert 	case 0:	/* all commands */
168638d5c833SDouglas Gilbert 		/* count number of commands */
168738d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
168838d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
168938d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
169038d5c833SDouglas Gilbert 				continue;
169138d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
169238d5c833SDouglas Gilbert 		}
169338d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
169438d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
169538d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
169638d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
169738d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
169838d5c833SDouglas Gilbert 				continue;
169938d5c833SDouglas Gilbert 			na = oip->num_attached;
170038d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
170138d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
170238d5c833SDouglas Gilbert 			if (rctd)
170338d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
170438d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
170538d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
170638d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
170738d5c833SDouglas Gilbert 			if (rctd)
170838d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
170938d5c833SDouglas Gilbert 			r_oip = oip;
171038d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
171138d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
171238d5c833SDouglas Gilbert 					continue;
171338d5c833SDouglas Gilbert 				offset += bump;
171438d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
171538d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
171638d5c833SDouglas Gilbert 				if (rctd)
171738d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
171838d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
171938d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
172038d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
172138d5c833SDouglas Gilbert 						   arr + offset + 6);
172238d5c833SDouglas Gilbert 				if (rctd)
172338d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
172438d5c833SDouglas Gilbert 							   arr + offset + 8);
172538d5c833SDouglas Gilbert 			}
172638d5c833SDouglas Gilbert 			oip = r_oip;
172738d5c833SDouglas Gilbert 			offset += bump;
172838d5c833SDouglas Gilbert 		}
172938d5c833SDouglas Gilbert 		break;
173038d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
173138d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
173238d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
173338d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
173438d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
173538d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
173638d5c833SDouglas Gilbert 			supp = 1;
173738d5c833SDouglas Gilbert 			offset = 4;
173838d5c833SDouglas Gilbert 		} else {
173938d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
174038d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
174138d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
174238d5c833SDouglas Gilbert 							     2, 2);
174338d5c833SDouglas Gilbert 					kfree(arr);
174438d5c833SDouglas Gilbert 					return check_condition_result;
174538d5c833SDouglas Gilbert 				}
174638d5c833SDouglas Gilbert 				req_sa = 0;
174738d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
174838d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
174938d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
175038d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
175138d5c833SDouglas Gilbert 				return check_condition_result;
175238d5c833SDouglas Gilbert 			}
175338d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
175438d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
175538d5c833SDouglas Gilbert 				supp = 3;
175638d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
175738d5c833SDouglas Gilbert 				na = oip->num_attached;
175838d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
175938d5c833SDouglas Gilbert 				     ++k, ++oip) {
176038d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
176138d5c833SDouglas Gilbert 						break;
176238d5c833SDouglas Gilbert 				}
176338d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
176438d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
176538d5c833SDouglas Gilbert 				na = oip->num_attached;
176638d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
176738d5c833SDouglas Gilbert 				     ++k, ++oip) {
176838d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
176938d5c833SDouglas Gilbert 						break;
177038d5c833SDouglas Gilbert 				}
177138d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
177238d5c833SDouglas Gilbert 			} else
177338d5c833SDouglas Gilbert 				supp = 3;
177438d5c833SDouglas Gilbert 			if (3 == supp) {
177538d5c833SDouglas Gilbert 				u = oip->len_mask[0];
177638d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
177738d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
177838d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
177938d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
178038d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
178138d5c833SDouglas Gilbert 				offset = 4 + u;
178238d5c833SDouglas Gilbert 			} else
178338d5c833SDouglas Gilbert 				offset = 4;
178438d5c833SDouglas Gilbert 		}
178538d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
178638d5c833SDouglas Gilbert 		if (rctd) {
178738d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
178838d5c833SDouglas Gilbert 			offset += 12;
178938d5c833SDouglas Gilbert 		}
179038d5c833SDouglas Gilbert 		break;
179138d5c833SDouglas Gilbert 	default:
179238d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
179338d5c833SDouglas Gilbert 		kfree(arr);
179438d5c833SDouglas Gilbert 		return check_condition_result;
179538d5c833SDouglas Gilbert 	}
179638d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
179738d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
179838d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
179938d5c833SDouglas Gilbert 	kfree(arr);
180038d5c833SDouglas Gilbert 	return errsts;
180138d5c833SDouglas Gilbert }
180238d5c833SDouglas Gilbert 
1803fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1804fd32119bSDouglas Gilbert 			  struct sdebug_dev_info *devip)
180538d5c833SDouglas Gilbert {
180638d5c833SDouglas Gilbert 	bool repd;
180738d5c833SDouglas Gilbert 	u32 alloc_len, len;
180838d5c833SDouglas Gilbert 	u8 arr[16];
180938d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
181038d5c833SDouglas Gilbert 
181138d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
181238d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
181338d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
181438d5c833SDouglas Gilbert 	if (alloc_len < 4) {
181538d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
181638d5c833SDouglas Gilbert 		return check_condition_result;
181738d5c833SDouglas Gilbert 	}
181838d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
181938d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
182038d5c833SDouglas Gilbert 	if (repd) {
182138d5c833SDouglas Gilbert 		arr[3] = 0xc;
182238d5c833SDouglas Gilbert 		len = 16;
182338d5c833SDouglas Gilbert 	} else
182438d5c833SDouglas Gilbert 		len = 4;
182538d5c833SDouglas Gilbert 
182638d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
182738d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
182838d5c833SDouglas Gilbert }
182938d5c833SDouglas Gilbert 
18301da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
18311da177e4SLinus Torvalds 
18321da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
18331da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
18341da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
18351da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
18361da177e4SLinus Torvalds 
18371da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
18381da177e4SLinus Torvalds 	if (1 == pcontrol)
18391da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
18401da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
18411da177e4SLinus Torvalds }
18421da177e4SLinus Torvalds 
18431da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
18441da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
18451da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
18461da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
18471da177e4SLinus Torvalds 
18481da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
18491da177e4SLinus Torvalds 	if (1 == pcontrol)
18501da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
18511da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
18521da177e4SLinus Torvalds }
18531da177e4SLinus Torvalds 
18541da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target)
18551da177e4SLinus Torvalds {       /* Format device page for mode_sense */
18561da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
18571da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
18581da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
18591da177e4SLinus Torvalds 
18601da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
1861773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
1862773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
1863773642d9SDouglas Gilbert 	if (sdebug_removable)
18641da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
18651da177e4SLinus Torvalds 	if (1 == pcontrol)
18661da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
18671da177e4SLinus Torvalds 	return sizeof(format_pg);
18681da177e4SLinus Torvalds }
18691da177e4SLinus Torvalds 
1870fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1871fd32119bSDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1872fd32119bSDouglas Gilbert 				     0, 0, 0, 0};
1873fd32119bSDouglas Gilbert 
18741da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
18751da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
1876cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1877cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1878cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
18791da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
18801da177e4SLinus Torvalds 
1881773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
1882cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
18831da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
18841da177e4SLinus Torvalds 	if (1 == pcontrol)
1885cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1886cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
1887cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
18881da177e4SLinus Torvalds 	return sizeof(caching_pg);
18891da177e4SLinus Torvalds }
18901da177e4SLinus Torvalds 
1891fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
1892fd32119bSDouglas Gilbert 				    0, 0, 0x2, 0x4b};
1893fd32119bSDouglas Gilbert 
18941da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
18951da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
1896c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1897c65b1445SDouglas Gilbert 				        0, 0, 0, 0};
1898c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
18991da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
19001da177e4SLinus Torvalds 
1901773642d9SDouglas Gilbert 	if (sdebug_dsense)
19021da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
1903c65b1445SDouglas Gilbert 	else
1904c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
1905c6a44287SMartin K. Petersen 
1906773642d9SDouglas Gilbert 	if (sdebug_ato)
1907c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1908c6a44287SMartin K. Petersen 
19091da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
19101da177e4SLinus Torvalds 	if (1 == pcontrol)
1911c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1912c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1913c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
19141da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
19151da177e4SLinus Torvalds }
19161da177e4SLinus Torvalds 
1917c65b1445SDouglas Gilbert 
19181da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
19191da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
1920c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
19211da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
1922c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1923c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
1924c65b1445SDouglas Gilbert 
19251da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
19261da177e4SLinus Torvalds 	if (1 == pcontrol)
1927c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1928c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1929c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
19301da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
19311da177e4SLinus Torvalds }
19321da177e4SLinus Torvalds 
1933c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1934c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
1935c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1936c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1937c65b1445SDouglas Gilbert 
1938c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1939c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1940c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1941c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
1942c65b1445SDouglas Gilbert }
1943c65b1445SDouglas Gilbert 
1944c65b1445SDouglas Gilbert 
1945c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1946c65b1445SDouglas Gilbert 			      int target_dev_id)
1947c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
1948c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1949c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1950773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1951773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1952c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
1953c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1954c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1955c65b1445SDouglas Gilbert 		    0, 1, 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 		    0x3, 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 		};
1962c65b1445SDouglas Gilbert 	int port_a, port_b;
1963c65b1445SDouglas Gilbert 
19641b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
19651b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
19661b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
19671b37bd60SDouglas Gilbert 	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
1968c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1969c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1970c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1971773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
1972773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
1973c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1974c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1975c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
1976c65b1445SDouglas Gilbert }
1977c65b1445SDouglas Gilbert 
1978c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1979c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
1980c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1981c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1982c65b1445SDouglas Gilbert 		};
1983c65b1445SDouglas Gilbert 
1984c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1985c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1986c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1987c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
1988c65b1445SDouglas Gilbert }
1989c65b1445SDouglas Gilbert 
19901da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
19911da177e4SLinus Torvalds 
1992fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp,
1993fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
19941da177e4SLinus Torvalds {
199523183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
19961da177e4SLinus Torvalds 	unsigned char dev_spec;
1997760f3b03SDouglas Gilbert 	int alloc_len, offset, len, target_dev_id;
1998c2248fc9SDouglas Gilbert 	int target = scp->device->id;
19991da177e4SLinus Torvalds 	unsigned char * ap;
20001da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
200101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2002760f3b03SDouglas Gilbert 	bool dbd, llbaa, msense_6, is_disk, bad_pcode;
20031da177e4SLinus Torvalds 
2004760f3b03SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
20051da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
20061da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
20071da177e4SLinus Torvalds 	subpcode = cmd[3];
20081da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
2009760f3b03SDouglas Gilbert 	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2010760f3b03SDouglas Gilbert 	is_disk = (sdebug_ptype == TYPE_DISK);
2011760f3b03SDouglas Gilbert 	if (is_disk && !dbd)
201223183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
201323183910SDouglas Gilbert 	else
201423183910SDouglas Gilbert 		bd_len = 0;
2015773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
20161da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
20171da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2018cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
20191da177e4SLinus Torvalds 		return check_condition_result;
20201da177e4SLinus Torvalds 	}
2021c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2022c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
2023b01f6f83SDouglas Gilbert 	/* for disks set DPOFUA bit and clear write protect (WP) bit */
2024760f3b03SDouglas Gilbert 	if (is_disk)
2025b01f6f83SDouglas Gilbert 		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
202623183910SDouglas Gilbert 	else
202723183910SDouglas Gilbert 		dev_spec = 0x0;
20281da177e4SLinus Torvalds 	if (msense_6) {
20291da177e4SLinus Torvalds 		arr[2] = dev_spec;
203023183910SDouglas Gilbert 		arr[3] = bd_len;
20311da177e4SLinus Torvalds 		offset = 4;
20321da177e4SLinus Torvalds 	} else {
20331da177e4SLinus Torvalds 		arr[3] = dev_spec;
203423183910SDouglas Gilbert 		if (16 == bd_len)
203523183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
203623183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
20371da177e4SLinus Torvalds 		offset = 8;
20381da177e4SLinus Torvalds 	}
20391da177e4SLinus Torvalds 	ap = arr + offset;
204028898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
204128898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
204228898873SFUJITA Tomonori 
204323183910SDouglas Gilbert 	if (8 == bd_len) {
2044773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
2045773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
2046773642d9SDouglas Gilbert 		else
2047773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
2048773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
204923183910SDouglas Gilbert 		offset += bd_len;
205023183910SDouglas Gilbert 		ap = arr + offset;
205123183910SDouglas Gilbert 	} else if (16 == bd_len) {
2052773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2053773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
205423183910SDouglas Gilbert 		offset += bd_len;
205523183910SDouglas Gilbert 		ap = arr + offset;
205623183910SDouglas Gilbert 	}
20571da177e4SLinus Torvalds 
2058c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2059c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
206022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
20611da177e4SLinus Torvalds 		return check_condition_result;
20621da177e4SLinus Torvalds 	}
2063760f3b03SDouglas Gilbert 	bad_pcode = false;
2064760f3b03SDouglas Gilbert 
20651da177e4SLinus Torvalds 	switch (pcode) {
20661da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
20671da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
20681da177e4SLinus Torvalds 		offset += len;
20691da177e4SLinus Torvalds 		break;
20701da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
20711da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
20721da177e4SLinus Torvalds 		offset += len;
20731da177e4SLinus Torvalds 		break;
20741da177e4SLinus Torvalds         case 0x3:       /* Format device page, direct access */
2075760f3b03SDouglas Gilbert 		if (is_disk) {
20761da177e4SLinus Torvalds 			len = resp_format_pg(ap, pcontrol, target);
20771da177e4SLinus Torvalds 			offset += len;
2078760f3b03SDouglas Gilbert 		} else
2079760f3b03SDouglas Gilbert 			bad_pcode = true;
20801da177e4SLinus Torvalds                 break;
20811da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
2082760f3b03SDouglas Gilbert 		if (is_disk) {
20831da177e4SLinus Torvalds 			len = resp_caching_pg(ap, pcontrol, target);
20841da177e4SLinus Torvalds 			offset += len;
2085760f3b03SDouglas Gilbert 		} else
2086760f3b03SDouglas Gilbert 			bad_pcode = true;
20871da177e4SLinus Torvalds 		break;
20881da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
20891da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
20901da177e4SLinus Torvalds 		offset += len;
20911da177e4SLinus Torvalds 		break;
2092c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2093c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
209422017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2095c65b1445SDouglas Gilbert 			return check_condition_result;
2096c65b1445SDouglas Gilbert 	        }
2097c65b1445SDouglas Gilbert 		len = 0;
2098c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2099c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2100c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2101c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2102c65b1445SDouglas Gilbert 						  target_dev_id);
2103c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2104c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2105c65b1445SDouglas Gilbert 		offset += len;
2106c65b1445SDouglas Gilbert 		break;
21071da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
21081da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
21091da177e4SLinus Torvalds 		offset += len;
21101da177e4SLinus Torvalds 		break;
21111da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2112c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
21131da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
21141da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
2115760f3b03SDouglas Gilbert 			if (is_disk) {
2116760f3b03SDouglas Gilbert 				len += resp_format_pg(ap + len, pcontrol,
2117760f3b03SDouglas Gilbert 						      target);
2118760f3b03SDouglas Gilbert 				len += resp_caching_pg(ap + len, pcontrol,
2119760f3b03SDouglas Gilbert 						       target);
2120760f3b03SDouglas Gilbert 			}
21211da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2122c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2123c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2124c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2125c65b1445SDouglas Gilbert 						  target, target_dev_id);
2126c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2127c65b1445SDouglas Gilbert 			}
21281da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2129760f3b03SDouglas Gilbert 			offset += len;
2130c65b1445SDouglas Gilbert 		} else {
213122017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2132c65b1445SDouglas Gilbert 			return check_condition_result;
2133c65b1445SDouglas Gilbert                 }
21341da177e4SLinus Torvalds 		break;
21351da177e4SLinus Torvalds 	default:
2136760f3b03SDouglas Gilbert 		bad_pcode = true;
2137760f3b03SDouglas Gilbert 		break;
2138760f3b03SDouglas Gilbert 	}
2139760f3b03SDouglas Gilbert 	if (bad_pcode) {
214022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
21411da177e4SLinus Torvalds 		return check_condition_result;
21421da177e4SLinus Torvalds 	}
21431da177e4SLinus Torvalds 	if (msense_6)
21441da177e4SLinus Torvalds 		arr[0] = offset - 1;
2145773642d9SDouglas Gilbert 	else
2146773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
21471da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
21481da177e4SLinus Torvalds }
21491da177e4SLinus Torvalds 
2150c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2151c65b1445SDouglas Gilbert 
2152fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp,
2153fd32119bSDouglas Gilbert 			    struct sdebug_dev_info *devip)
2154c65b1445SDouglas Gilbert {
2155c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2156c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2157c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
215801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2159c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2160c65b1445SDouglas Gilbert 
2161c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2162c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2163c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2164773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2165c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
216622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2167c65b1445SDouglas Gilbert 		return check_condition_result;
2168c65b1445SDouglas Gilbert 	}
2169c65b1445SDouglas Gilbert         res = fetch_to_dev_buffer(scp, arr, param_len);
2170c65b1445SDouglas Gilbert         if (-1 == res)
2171773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2172773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2173cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2174cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2175cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2176773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2177773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
217823183910SDouglas Gilbert 	if (md_len > 2) {
217922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2180c65b1445SDouglas Gilbert 		return check_condition_result;
2181c65b1445SDouglas Gilbert 	}
2182c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2183c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2184c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2185c65b1445SDouglas Gilbert 	if (ps) {
218622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2187c65b1445SDouglas Gilbert 		return check_condition_result;
2188c65b1445SDouglas Gilbert 	}
2189c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2190773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2191c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2192c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2193cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2194c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2195c65b1445SDouglas Gilbert 		return check_condition_result;
2196c65b1445SDouglas Gilbert 	}
2197c65b1445SDouglas Gilbert 	switch (mpage) {
2198cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2199cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2200cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2201cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2202cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2203cbf67842SDouglas Gilbert 		}
2204cbf67842SDouglas Gilbert 		break;
2205c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2206c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2207c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2208c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
2209773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2210cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2211c65b1445SDouglas Gilbert 		}
2212c65b1445SDouglas Gilbert 		break;
2213c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2214c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2215c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2216c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2217cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2218c65b1445SDouglas Gilbert 		}
2219c65b1445SDouglas Gilbert 		break;
2220c65b1445SDouglas Gilbert 	default:
2221c65b1445SDouglas Gilbert 		break;
2222c65b1445SDouglas Gilbert 	}
222322017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2224c65b1445SDouglas Gilbert 	return check_condition_result;
2225cbf67842SDouglas Gilbert set_mode_changed_ua:
2226cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2227cbf67842SDouglas Gilbert 	return 0;
2228c65b1445SDouglas Gilbert }
2229c65b1445SDouglas Gilbert 
2230c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr)
2231c65b1445SDouglas Gilbert {
2232c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2233c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2234c65b1445SDouglas Gilbert 		};
2235c65b1445SDouglas Gilbert 
2236c65b1445SDouglas Gilbert         memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2237c65b1445SDouglas Gilbert         return sizeof(temp_l_pg);
2238c65b1445SDouglas Gilbert }
2239c65b1445SDouglas Gilbert 
2240c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr)
2241c65b1445SDouglas Gilbert {
2242c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2243c65b1445SDouglas Gilbert 		};
2244c65b1445SDouglas Gilbert 
2245c65b1445SDouglas Gilbert         memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2246c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2247c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2248c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2249c65b1445SDouglas Gilbert 	}
2250c65b1445SDouglas Gilbert         return sizeof(ie_l_pg);
2251c65b1445SDouglas Gilbert }
2252c65b1445SDouglas Gilbert 
2253c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2254c65b1445SDouglas Gilbert 
2255c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp,
2256c65b1445SDouglas Gilbert                           struct sdebug_dev_info * devip)
2257c65b1445SDouglas Gilbert {
2258c2248fc9SDouglas Gilbert 	int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n;
2259c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
226001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2261c65b1445SDouglas Gilbert 
2262c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2263c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2264c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2265c65b1445SDouglas Gilbert 	if (ppc || sp) {
226622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2267c65b1445SDouglas Gilbert 		return check_condition_result;
2268c65b1445SDouglas Gilbert 	}
2269c65b1445SDouglas Gilbert 	pcontrol = (cmd[2] & 0xc0) >> 6;
2270c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
227123183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2272773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2273c65b1445SDouglas Gilbert 	arr[0] = pcode;
227423183910SDouglas Gilbert 	if (0 == subpcode) {
2275c65b1445SDouglas Gilbert 		switch (pcode) {
2276c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2277c65b1445SDouglas Gilbert 			n = 4;
2278c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2279c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2280c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2281c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2282c65b1445SDouglas Gilbert 			break;
2283c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2284c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2285c65b1445SDouglas Gilbert 			break;
2286c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2287c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2288c65b1445SDouglas Gilbert 			break;
2289c65b1445SDouglas Gilbert 		default:
229022017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2291c65b1445SDouglas Gilbert 			return check_condition_result;
2292c65b1445SDouglas Gilbert 		}
229323183910SDouglas Gilbert 	} else if (0xff == subpcode) {
229423183910SDouglas Gilbert 		arr[0] |= 0x40;
229523183910SDouglas Gilbert 		arr[1] = subpcode;
229623183910SDouglas Gilbert 		switch (pcode) {
229723183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
229823183910SDouglas Gilbert 			n = 4;
229923183910SDouglas Gilbert 			arr[n++] = 0x0;
230023183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
230123183910SDouglas Gilbert 			arr[n++] = 0x0;
230223183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
230323183910SDouglas Gilbert 			arr[n++] = 0xd;
230423183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
230523183910SDouglas Gilbert 			arr[n++] = 0x2f;
230623183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
230723183910SDouglas Gilbert 			arr[3] = n - 4;
230823183910SDouglas Gilbert 			break;
230923183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
231023183910SDouglas Gilbert 			n = 4;
231123183910SDouglas Gilbert 			arr[n++] = 0xd;
231223183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
231323183910SDouglas Gilbert 			arr[3] = n - 4;
231423183910SDouglas Gilbert 			break;
231523183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
231623183910SDouglas Gilbert 			n = 4;
231723183910SDouglas Gilbert 			arr[n++] = 0x2f;
231823183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
231923183910SDouglas Gilbert 			arr[3] = n - 4;
232023183910SDouglas Gilbert 			break;
232123183910SDouglas Gilbert 		default:
232222017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
232323183910SDouglas Gilbert 			return check_condition_result;
232423183910SDouglas Gilbert 		}
232523183910SDouglas Gilbert 	} else {
232622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
232723183910SDouglas Gilbert 		return check_condition_result;
232823183910SDouglas Gilbert 	}
2329773642d9SDouglas Gilbert 	len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
2330c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
2331c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
2332c65b1445SDouglas Gilbert }
2333c65b1445SDouglas Gilbert 
2334cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp,
233519789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
23361da177e4SLinus Torvalds {
2337c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
233822017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
23391da177e4SLinus Torvalds 		return check_condition_result;
23401da177e4SLinus Torvalds 	}
2341c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2342c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
234322017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2344cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2345c65b1445SDouglas Gilbert 		return check_condition_result;
2346c65b1445SDouglas Gilbert 	}
234719789100SFUJITA Tomonori 	return 0;
234819789100SFUJITA Tomonori }
234919789100SFUJITA Tomonori 
2350a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
2351fd32119bSDouglas Gilbert static int do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num,
2352fd32119bSDouglas Gilbert 			    bool do_write)
235319789100SFUJITA Tomonori {
235419789100SFUJITA Tomonori 	int ret;
2355c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2356a4517511SAkinobu Mita 	struct scsi_data_buffer *sdb;
2357a4517511SAkinobu Mita 	enum dma_data_direction dir;
235819789100SFUJITA Tomonori 
2359c2248fc9SDouglas Gilbert 	if (do_write) {
2360a4517511SAkinobu Mita 		sdb = scsi_out(scmd);
2361a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
2362a4517511SAkinobu Mita 	} else {
2363a4517511SAkinobu Mita 		sdb = scsi_in(scmd);
2364a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2365a4517511SAkinobu Mita 	}
2366a4517511SAkinobu Mita 
2367a4517511SAkinobu Mita 	if (!sdb->length)
2368a4517511SAkinobu Mita 		return 0;
2369a4517511SAkinobu Mita 	if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2370a4517511SAkinobu Mita 		return -1;
237119789100SFUJITA Tomonori 
237219789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
237319789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
237419789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
237519789100SFUJITA Tomonori 
2376386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2377773642d9SDouglas Gilbert 		   fake_storep + (block * sdebug_sector_size),
2378773642d9SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, 0, do_write);
2379773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2380a4517511SAkinobu Mita 		return ret;
2381a4517511SAkinobu Mita 
2382a4517511SAkinobu Mita 	if (rest) {
2383386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2384773642d9SDouglas Gilbert 			    fake_storep, rest * sdebug_sector_size,
2385773642d9SDouglas Gilbert 			    (num - rest) * sdebug_sector_size, do_write);
2386a4517511SAkinobu Mita 	}
238719789100SFUJITA Tomonori 
238819789100SFUJITA Tomonori 	return ret;
238919789100SFUJITA Tomonori }
239019789100SFUJITA Tomonori 
239138d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of
239238d5c833SDouglas Gilbert  * arr into fake_store(lba,num) and return true. If comparison fails then
239338d5c833SDouglas Gilbert  * return false. */
2394fd32119bSDouglas Gilbert static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
239538d5c833SDouglas Gilbert {
239638d5c833SDouglas Gilbert 	bool res;
239738d5c833SDouglas Gilbert 	u64 block, rest = 0;
239838d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2399773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
240038d5c833SDouglas Gilbert 
240138d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
240238d5c833SDouglas Gilbert 	if (block + num > store_blks)
240338d5c833SDouglas Gilbert 		rest = block + num - store_blks;
240438d5c833SDouglas Gilbert 
240538d5c833SDouglas Gilbert 	res = !memcmp(fake_storep + (block * lb_size), arr,
240638d5c833SDouglas Gilbert 		      (num - rest) * lb_size);
240738d5c833SDouglas Gilbert 	if (!res)
240838d5c833SDouglas Gilbert 		return res;
240938d5c833SDouglas Gilbert 	if (rest)
241038d5c833SDouglas Gilbert 		res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
241138d5c833SDouglas Gilbert 			     rest * lb_size);
241238d5c833SDouglas Gilbert 	if (!res)
241338d5c833SDouglas Gilbert 		return res;
241438d5c833SDouglas Gilbert 	arr += num * lb_size;
241538d5c833SDouglas Gilbert 	memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
241638d5c833SDouglas Gilbert 	if (rest)
241738d5c833SDouglas Gilbert 		memcpy(fake_storep, arr + ((num - rest) * lb_size),
241838d5c833SDouglas Gilbert 		       rest * lb_size);
241938d5c833SDouglas Gilbert 	return res;
242038d5c833SDouglas Gilbert }
242138d5c833SDouglas Gilbert 
242251d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2423beb40ea4SAkinobu Mita {
242451d648afSAkinobu Mita 	__be16 csum;
2425beb40ea4SAkinobu Mita 
2426773642d9SDouglas Gilbert 	if (sdebug_guard)
242751d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
242851d648afSAkinobu Mita 	else
2429beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
243051d648afSAkinobu Mita 
2431beb40ea4SAkinobu Mita 	return csum;
2432beb40ea4SAkinobu Mita }
2433beb40ea4SAkinobu Mita 
24346ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
2435beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
2436beb40ea4SAkinobu Mita {
2437773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
2438beb40ea4SAkinobu Mita 
2439beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
2440c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
2441beb40ea4SAkinobu Mita 			(unsigned long)sector,
2442beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
2443beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
2444beb40ea4SAkinobu Mita 		return 0x01;
2445beb40ea4SAkinobu Mita 	}
24468475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
2447beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
2448c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2449c1287970STomas Winkler 			(unsigned long)sector);
2450beb40ea4SAkinobu Mita 		return 0x03;
2451beb40ea4SAkinobu Mita 	}
24528475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2453beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
2454c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2455c1287970STomas Winkler 			(unsigned long)sector);
2456beb40ea4SAkinobu Mita 		return 0x03;
2457beb40ea4SAkinobu Mita 	}
2458beb40ea4SAkinobu Mita 	return 0;
2459beb40ea4SAkinobu Mita }
2460beb40ea4SAkinobu Mita 
2461bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
246265f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
2463c6a44287SMartin K. Petersen {
2464be4e11beSAkinobu Mita 	size_t resid;
2465c6a44287SMartin K. Petersen 	void *paddr;
246614faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
2467be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
2468c6a44287SMartin K. Petersen 
2469e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
2470e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
2471c6a44287SMartin K. Petersen 
2472be4e11beSAkinobu Mita 	sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2473be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2474be4e11beSAkinobu Mita 			(read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2475be4e11beSAkinobu Mita 
2476be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
2477be4e11beSAkinobu Mita 		size_t len = min(miter.length, resid);
247814faa944SAkinobu Mita 		void *start = dif_store(sector);
2479be4e11beSAkinobu Mita 		size_t rest = 0;
248014faa944SAkinobu Mita 
248114faa944SAkinobu Mita 		if (dif_store_end < start + len)
248214faa944SAkinobu Mita 			rest = start + len - dif_store_end;
2483c6a44287SMartin K. Petersen 
2484be4e11beSAkinobu Mita 		paddr = miter.addr;
248514faa944SAkinobu Mita 
248665f72f2aSAkinobu Mita 		if (read)
248765f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
248865f72f2aSAkinobu Mita 		else
248965f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
249065f72f2aSAkinobu Mita 
249165f72f2aSAkinobu Mita 		if (rest) {
249265f72f2aSAkinobu Mita 			if (read)
249314faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
249465f72f2aSAkinobu Mita 			else
249565f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
249665f72f2aSAkinobu Mita 		}
2497c6a44287SMartin K. Petersen 
2498e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
2499c6a44287SMartin K. Petersen 		resid -= len;
2500c6a44287SMartin K. Petersen 	}
2501be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
2502bb8c063cSAkinobu Mita }
2503c6a44287SMartin K. Petersen 
2504bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2505bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
2506bb8c063cSAkinobu Mita {
2507bb8c063cSAkinobu Mita 	unsigned int i;
25086ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
2509bb8c063cSAkinobu Mita 	sector_t sector;
2510bb8c063cSAkinobu Mita 
2511c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
2512bb8c063cSAkinobu Mita 		int ret;
2513bb8c063cSAkinobu Mita 
2514bb8c063cSAkinobu Mita 		sector = start_sec + i;
2515bb8c063cSAkinobu Mita 		sdt = dif_store(sector);
2516bb8c063cSAkinobu Mita 
251751d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
2518bb8c063cSAkinobu Mita 			continue;
2519bb8c063cSAkinobu Mita 
2520bb8c063cSAkinobu Mita 		ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2521bb8c063cSAkinobu Mita 		if (ret) {
2522bb8c063cSAkinobu Mita 			dif_errors++;
2523bb8c063cSAkinobu Mita 			return ret;
2524bb8c063cSAkinobu Mita 		}
2525bb8c063cSAkinobu Mita 	}
2526bb8c063cSAkinobu Mita 
252765f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, true);
2528c6a44287SMartin K. Petersen 	dix_reads++;
2529c6a44287SMartin K. Petersen 
2530c6a44287SMartin K. Petersen 	return 0;
2531c6a44287SMartin K. Petersen }
2532c6a44287SMartin K. Petersen 
2533fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
253419789100SFUJITA Tomonori {
2535c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2536c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
2537c2248fc9SDouglas Gilbert 	u64 lba;
2538c2248fc9SDouglas Gilbert 	u32 num;
2539c2248fc9SDouglas Gilbert 	u32 ei_lba;
254019789100SFUJITA Tomonori 	unsigned long iflags;
254119789100SFUJITA Tomonori 	int ret;
2542c2248fc9SDouglas Gilbert 	bool check_prot;
254319789100SFUJITA Tomonori 
2544c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2545c2248fc9SDouglas Gilbert 	case READ_16:
2546c2248fc9SDouglas Gilbert 		ei_lba = 0;
2547c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2548c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2549c2248fc9SDouglas Gilbert 		check_prot = true;
2550c2248fc9SDouglas Gilbert 		break;
2551c2248fc9SDouglas Gilbert 	case READ_10:
2552c2248fc9SDouglas Gilbert 		ei_lba = 0;
2553c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2554c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2555c2248fc9SDouglas Gilbert 		check_prot = true;
2556c2248fc9SDouglas Gilbert 		break;
2557c2248fc9SDouglas Gilbert 	case READ_6:
2558c2248fc9SDouglas Gilbert 		ei_lba = 0;
2559c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2560c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2561c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2562c2248fc9SDouglas Gilbert 		check_prot = true;
2563c2248fc9SDouglas Gilbert 		break;
2564c2248fc9SDouglas Gilbert 	case READ_12:
2565c2248fc9SDouglas Gilbert 		ei_lba = 0;
2566c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2567c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2568c2248fc9SDouglas Gilbert 		check_prot = true;
2569c2248fc9SDouglas Gilbert 		break;
2570c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
2571c2248fc9SDouglas Gilbert 		ei_lba = 0;
2572c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2573c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2574c2248fc9SDouglas Gilbert 		check_prot = false;
2575c2248fc9SDouglas Gilbert 		break;
2576c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
2577c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2578c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2579c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2580c2248fc9SDouglas Gilbert 		check_prot = false;
2581c2248fc9SDouglas Gilbert 		break;
2582c2248fc9SDouglas Gilbert 	}
2583f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
25848475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2585c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2586c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2587c2248fc9SDouglas Gilbert 			return check_condition_result;
2588c2248fc9SDouglas Gilbert 		}
25898475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
25908475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
2591c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2592c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2593c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2594c2248fc9SDouglas Gilbert 	}
2595f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
2596c4837394SDouglas Gilbert 		sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
2597c2248fc9SDouglas Gilbert 
2598c4837394SDouglas Gilbert 		if (sqcp) {
2599c4837394SDouglas Gilbert 			if (sqcp->inj_short)
2600c2248fc9SDouglas Gilbert 				num /= 2;
2601c2248fc9SDouglas Gilbert 		}
2602c4837394SDouglas Gilbert 	} else
2603c4837394SDouglas Gilbert 		sqcp = NULL;
2604c2248fc9SDouglas Gilbert 
2605c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2606f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
2607c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2608c2248fc9SDouglas Gilbert 		return check_condition_result;
2609c2248fc9SDouglas Gilbert 	}
2610c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2611f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
2612c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2613c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2614c2248fc9SDouglas Gilbert 		return check_condition_result;
2615c2248fc9SDouglas Gilbert 	}
261619789100SFUJITA Tomonori 
2617f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
261832f7ef73SDouglas Gilbert 		     (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
2619f46eb0e9SDouglas Gilbert 		     ((lba + num) > OPT_MEDIUM_ERR_ADDR))) {
2620c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
2621c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
2622c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
2623c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2624c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
262532f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
262632f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
2627c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
2628c65b1445SDouglas Gilbert 		}
2629c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
26301da177e4SLinus Torvalds 		return check_condition_result;
26311da177e4SLinus Torvalds 	}
2632c6a44287SMartin K. Petersen 
26336c78cc06SAkinobu Mita 	read_lock_irqsave(&atomic_rw, iflags);
26346c78cc06SAkinobu Mita 
2635c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2636f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
2637c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
2638c6a44287SMartin K. Petersen 
2639c6a44287SMartin K. Petersen 		if (prot_ret) {
26406c78cc06SAkinobu Mita 			read_unlock_irqrestore(&atomic_rw, iflags);
2641c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
2642c6a44287SMartin K. Petersen 			return illegal_condition_result;
2643c6a44287SMartin K. Petersen 		}
2644c6a44287SMartin K. Petersen 	}
2645c6a44287SMartin K. Petersen 
2646c2248fc9SDouglas Gilbert 	ret = do_device_access(scp, lba, num, false);
26471da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
2648f46eb0e9SDouglas Gilbert 	if (unlikely(ret == -1))
2649a4517511SAkinobu Mita 		return DID_ERROR << 16;
2650a4517511SAkinobu Mita 
2651c2248fc9SDouglas Gilbert 	scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
2652a4517511SAkinobu Mita 
2653c4837394SDouglas Gilbert 	if (unlikely(sqcp)) {
2654c4837394SDouglas Gilbert 		if (sqcp->inj_recovered) {
2655c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
2656c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
2657c2248fc9SDouglas Gilbert 			return check_condition_result;
2658c4837394SDouglas Gilbert 		} else if (sqcp->inj_transport) {
2659c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND,
2660c2248fc9SDouglas Gilbert 					TRANSPORT_PROBLEM, ACK_NAK_TO);
2661c2248fc9SDouglas Gilbert 			return check_condition_result;
2662c4837394SDouglas Gilbert 		} else if (sqcp->inj_dif) {
2663c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
2664c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2665c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2666c4837394SDouglas Gilbert 		} else if (sqcp->inj_dix) {
2667c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2668c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2669c2248fc9SDouglas Gilbert 		}
2670c2248fc9SDouglas Gilbert 	}
2671a4517511SAkinobu Mita 	return 0;
26721da177e4SLinus Torvalds }
26731da177e4SLinus Torvalds 
267458a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len)
2675c6a44287SMartin K. Petersen {
2676cbf67842SDouglas Gilbert 	int i, j, n;
2677c6a44287SMartin K. Petersen 
2678cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
2679c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
2680cbf67842SDouglas Gilbert 		char b[128];
2681c6a44287SMartin K. Petersen 
2682cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
2683c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
2684c6a44287SMartin K. Petersen 
2685cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
2686cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2687cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
2688cbf67842SDouglas Gilbert 			else
2689cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2690cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
2691cbf67842SDouglas Gilbert 		}
2692cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
2693c6a44287SMartin K. Petersen 	}
2694c6a44287SMartin K. Petersen }
2695c6a44287SMartin K. Petersen 
2696c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
2697395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
2698c6a44287SMartin K. Petersen {
2699be4e11beSAkinobu Mita 	int ret;
27006ebf105cSChristoph Hellwig 	struct t10_pi_tuple *sdt;
2701be4e11beSAkinobu Mita 	void *daddr;
270265f72f2aSAkinobu Mita 	sector_t sector = start_sec;
2703c6a44287SMartin K. Petersen 	int ppage_offset;
2704be4e11beSAkinobu Mita 	int dpage_offset;
2705be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
2706be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
2707c6a44287SMartin K. Petersen 
2708c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
2709c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2710c6a44287SMartin K. Petersen 
2711be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2712be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
2713be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2714be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2715be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2716c6a44287SMartin K. Petersen 
2717be4e11beSAkinobu Mita 	/* For each protection page */
2718be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
2719be4e11beSAkinobu Mita 		dpage_offset = 0;
2720be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
2721be4e11beSAkinobu Mita 			ret = 0x01;
2722be4e11beSAkinobu Mita 			goto out;
2723c6a44287SMartin K. Petersen 		}
2724c6a44287SMartin K. Petersen 
2725be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
27266ebf105cSChristoph Hellwig 		     ppage_offset += sizeof(struct t10_pi_tuple)) {
2727be4e11beSAkinobu Mita 			/* If we're at the end of the current
2728be4e11beSAkinobu Mita 			 * data page advance to the next one
2729be4e11beSAkinobu Mita 			 */
2730be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
2731be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
2732be4e11beSAkinobu Mita 					ret = 0x01;
2733be4e11beSAkinobu Mita 					goto out;
2734be4e11beSAkinobu Mita 				}
2735be4e11beSAkinobu Mita 				dpage_offset = 0;
2736be4e11beSAkinobu Mita 			}
2737c6a44287SMartin K. Petersen 
2738be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
2739be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
2740be4e11beSAkinobu Mita 
2741be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
2742beb40ea4SAkinobu Mita 			if (ret) {
2743773642d9SDouglas Gilbert 				dump_sector(daddr, sdebug_sector_size);
2744395cef03SMartin K. Petersen 				goto out;
2745395cef03SMartin K. Petersen 			}
2746395cef03SMartin K. Petersen 
2747c6a44287SMartin K. Petersen 			sector++;
2748395cef03SMartin K. Petersen 			ei_lba++;
2749773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
2750c6a44287SMartin K. Petersen 		}
2751be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
2752be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
2753c6a44287SMartin K. Petersen 	}
2754be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2755c6a44287SMartin K. Petersen 
275665f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
2757c6a44287SMartin K. Petersen 	dix_writes++;
2758c6a44287SMartin K. Petersen 
2759c6a44287SMartin K. Petersen 	return 0;
2760c6a44287SMartin K. Petersen 
2761c6a44287SMartin K. Petersen out:
2762c6a44287SMartin K. Petersen 	dif_errors++;
2763be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
2764be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2765c6a44287SMartin K. Petersen 	return ret;
2766c6a44287SMartin K. Petersen }
2767c6a44287SMartin K. Petersen 
2768b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
2769b90ebc3dSAkinobu Mita {
2770773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2771773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2772773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
2773b90ebc3dSAkinobu Mita 	return lba;
2774b90ebc3dSAkinobu Mita }
2775b90ebc3dSAkinobu Mita 
2776b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
2777b90ebc3dSAkinobu Mita {
2778773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
2779a027b5b9SAkinobu Mita 
2780773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2781773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
2782a027b5b9SAkinobu Mita 	return lba;
2783a027b5b9SAkinobu Mita }
2784a027b5b9SAkinobu Mita 
278544d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
278644d92694SMartin K. Petersen {
2787b90ebc3dSAkinobu Mita 	sector_t end;
2788b90ebc3dSAkinobu Mita 	unsigned int mapped;
2789b90ebc3dSAkinobu Mita 	unsigned long index;
2790b90ebc3dSAkinobu Mita 	unsigned long next;
279144d92694SMartin K. Petersen 
2792b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
2793b90ebc3dSAkinobu Mita 	mapped = test_bit(index, map_storep);
279444d92694SMartin K. Petersen 
279544d92694SMartin K. Petersen 	if (mapped)
2796b90ebc3dSAkinobu Mita 		next = find_next_zero_bit(map_storep, map_size, index);
279744d92694SMartin K. Petersen 	else
2798b90ebc3dSAkinobu Mita 		next = find_next_bit(map_storep, map_size, index);
279944d92694SMartin K. Petersen 
2800b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
280144d92694SMartin K. Petersen 	*num = end - lba;
280244d92694SMartin K. Petersen 	return mapped;
280344d92694SMartin K. Petersen }
280444d92694SMartin K. Petersen 
280544d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
280644d92694SMartin K. Petersen {
280744d92694SMartin K. Petersen 	sector_t end = lba + len;
280844d92694SMartin K. Petersen 
280944d92694SMartin K. Petersen 	while (lba < end) {
2810b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
281144d92694SMartin K. Petersen 
2812b90ebc3dSAkinobu Mita 		if (index < map_size)
2813b90ebc3dSAkinobu Mita 			set_bit(index, map_storep);
281444d92694SMartin K. Petersen 
2815b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
281644d92694SMartin K. Petersen 	}
281744d92694SMartin K. Petersen }
281844d92694SMartin K. Petersen 
281944d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
282044d92694SMartin K. Petersen {
282144d92694SMartin K. Petersen 	sector_t end = lba + len;
282244d92694SMartin K. Petersen 
282344d92694SMartin K. Petersen 	while (lba < end) {
2824b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
282544d92694SMartin K. Petersen 
2826b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
2827773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
2828b90ebc3dSAkinobu Mita 		    index < map_size) {
2829b90ebc3dSAkinobu Mita 			clear_bit(index, map_storep);
2830760f3b03SDouglas Gilbert 			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
2831be1dd78dSEric Sandeen 				memset(fake_storep +
2832760f3b03SDouglas Gilbert 				       lba * sdebug_sector_size,
2833760f3b03SDouglas Gilbert 				       (sdebug_lbprz & 1) ? 0 : 0xff,
2834773642d9SDouglas Gilbert 				       sdebug_sector_size *
2835773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2836be1dd78dSEric Sandeen 			}
2837e9926b43SAkinobu Mita 			if (dif_storep) {
2838e9926b43SAkinobu Mita 				memset(dif_storep + lba, 0xff,
2839e9926b43SAkinobu Mita 				       sizeof(*dif_storep) *
2840773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2841e9926b43SAkinobu Mita 			}
2842b90ebc3dSAkinobu Mita 		}
2843b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
284444d92694SMartin K. Petersen 	}
284544d92694SMartin K. Petersen }
284644d92694SMartin K. Petersen 
2847fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
28481da177e4SLinus Torvalds {
2849c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2850c2248fc9SDouglas Gilbert 	u64 lba;
2851c2248fc9SDouglas Gilbert 	u32 num;
2852c2248fc9SDouglas Gilbert 	u32 ei_lba;
28531da177e4SLinus Torvalds 	unsigned long iflags;
285419789100SFUJITA Tomonori 	int ret;
2855c2248fc9SDouglas Gilbert 	bool check_prot;
28561da177e4SLinus Torvalds 
2857c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2858c2248fc9SDouglas Gilbert 	case WRITE_16:
2859c2248fc9SDouglas Gilbert 		ei_lba = 0;
2860c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2861c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2862c2248fc9SDouglas Gilbert 		check_prot = true;
2863c2248fc9SDouglas Gilbert 		break;
2864c2248fc9SDouglas Gilbert 	case WRITE_10:
2865c2248fc9SDouglas Gilbert 		ei_lba = 0;
2866c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2867c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2868c2248fc9SDouglas Gilbert 		check_prot = true;
2869c2248fc9SDouglas Gilbert 		break;
2870c2248fc9SDouglas Gilbert 	case WRITE_6:
2871c2248fc9SDouglas Gilbert 		ei_lba = 0;
2872c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2873c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2874c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2875c2248fc9SDouglas Gilbert 		check_prot = true;
2876c2248fc9SDouglas Gilbert 		break;
2877c2248fc9SDouglas Gilbert 	case WRITE_12:
2878c2248fc9SDouglas Gilbert 		ei_lba = 0;
2879c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2880c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2881c2248fc9SDouglas Gilbert 		check_prot = true;
2882c2248fc9SDouglas Gilbert 		break;
2883c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
2884c2248fc9SDouglas Gilbert 		ei_lba = 0;
2885c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2886c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2887c2248fc9SDouglas Gilbert 		check_prot = false;
2888c2248fc9SDouglas Gilbert 		break;
2889c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
2890c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2891c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2892c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2893c2248fc9SDouglas Gilbert 		check_prot = false;
2894c2248fc9SDouglas Gilbert 		break;
2895c2248fc9SDouglas Gilbert 	}
2896f46eb0e9SDouglas Gilbert 	if (unlikely(have_dif_prot && check_prot)) {
28978475c811SChristoph Hellwig 		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
2898c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2899c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2900c2248fc9SDouglas Gilbert 			return check_condition_result;
2901c2248fc9SDouglas Gilbert 		}
29028475c811SChristoph Hellwig 		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
29038475c811SChristoph Hellwig 		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
2904c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2905c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2906c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2907c2248fc9SDouglas Gilbert 	}
2908c2248fc9SDouglas Gilbert 
2909c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2910f46eb0e9SDouglas Gilbert 	if (unlikely(lba + num > sdebug_capacity)) {
2911c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2912c2248fc9SDouglas Gilbert 		return check_condition_result;
2913c2248fc9SDouglas Gilbert 	}
2914c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2915f46eb0e9SDouglas Gilbert 	if (unlikely(num > sdebug_store_sectors)) {
2916c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2917c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2918c2248fc9SDouglas Gilbert 		return check_condition_result;
2919c2248fc9SDouglas Gilbert 	}
29201da177e4SLinus Torvalds 
29216c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
29226c78cc06SAkinobu Mita 
2923c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2924f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
2925c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
2926c6a44287SMartin K. Petersen 
2927c6a44287SMartin K. Petersen 		if (prot_ret) {
29286c78cc06SAkinobu Mita 			write_unlock_irqrestore(&atomic_rw, iflags);
2929c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
2930c6a44287SMartin K. Petersen 			return illegal_condition_result;
2931c6a44287SMartin K. Petersen 		}
2932c6a44287SMartin K. Petersen 	}
2933c6a44287SMartin K. Petersen 
2934c2248fc9SDouglas Gilbert 	ret = do_device_access(scp, lba, num, true);
2935f46eb0e9SDouglas Gilbert 	if (unlikely(scsi_debug_lbp()))
293644d92694SMartin K. Petersen 		map_region(lba, num);
29371da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
2938f46eb0e9SDouglas Gilbert 	if (unlikely(-1 == ret))
2939773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2940c4837394SDouglas Gilbert 	else if (unlikely(sdebug_verbose &&
2941c4837394SDouglas Gilbert 			  (ret < (num * sdebug_sector_size))))
2942c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2943cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
2944773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
294544d92694SMartin K. Petersen 
2946f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_any_injecting_opt)) {
2947c4837394SDouglas Gilbert 		struct sdebug_queued_cmd *sqcp =
2948c4837394SDouglas Gilbert 				(struct sdebug_queued_cmd *)scp->host_scribble;
2949c2248fc9SDouglas Gilbert 
2950c4837394SDouglas Gilbert 		if (sqcp) {
2951c4837394SDouglas Gilbert 			if (sqcp->inj_recovered) {
2952c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, RECOVERED_ERROR,
2953c2248fc9SDouglas Gilbert 						THRESHOLD_EXCEEDED, 0);
2954c2248fc9SDouglas Gilbert 				return check_condition_result;
2955c4837394SDouglas Gilbert 			} else if (sqcp->inj_dif) {
2956c2248fc9SDouglas Gilbert 				/* Logical block guard check failed */
2957c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2958c2248fc9SDouglas Gilbert 				return illegal_condition_result;
2959c4837394SDouglas Gilbert 			} else if (sqcp->inj_dix) {
2960c2248fc9SDouglas Gilbert 				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2961c2248fc9SDouglas Gilbert 				return illegal_condition_result;
2962c2248fc9SDouglas Gilbert 			}
2963c2248fc9SDouglas Gilbert 		}
2964c4837394SDouglas Gilbert 	}
29651da177e4SLinus Torvalds 	return 0;
29661da177e4SLinus Torvalds }
29671da177e4SLinus Torvalds 
2968fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
2969fd32119bSDouglas Gilbert 			   u32 ei_lba, bool unmap, bool ndob)
297044d92694SMartin K. Petersen {
297144d92694SMartin K. Petersen 	unsigned long iflags;
297244d92694SMartin K. Petersen 	unsigned long long i;
297344d92694SMartin K. Petersen 	int ret;
2974773642d9SDouglas Gilbert 	u64 lba_off;
297544d92694SMartin K. Petersen 
2976c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num);
297744d92694SMartin K. Petersen 	if (ret)
297844d92694SMartin K. Petersen 		return ret;
297944d92694SMartin K. Petersen 
298044d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
298144d92694SMartin K. Petersen 
29829ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
298344d92694SMartin K. Petersen 		unmap_region(lba, num);
298444d92694SMartin K. Petersen 		goto out;
298544d92694SMartin K. Petersen 	}
298644d92694SMartin K. Petersen 
2987773642d9SDouglas Gilbert 	lba_off = lba * sdebug_sector_size;
2988c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
2989c2248fc9SDouglas Gilbert 	if (ndob) {
2990773642d9SDouglas Gilbert 		memset(fake_storep + lba_off, 0, sdebug_sector_size);
2991c2248fc9SDouglas Gilbert 		ret = 0;
2992c2248fc9SDouglas Gilbert 	} else
2993773642d9SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
2994773642d9SDouglas Gilbert 					  sdebug_sector_size);
299544d92694SMartin K. Petersen 
299644d92694SMartin K. Petersen 	if (-1 == ret) {
299744d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
2998773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2999773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
3000c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3001cbf67842SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
3002cbf67842SDouglas Gilbert 			    my_name, "write same",
3003773642d9SDouglas Gilbert 			    num * sdebug_sector_size, ret);
300444d92694SMartin K. Petersen 
300544d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
300644d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
3007773642d9SDouglas Gilbert 		memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
3008773642d9SDouglas Gilbert 		       fake_storep + lba_off,
3009773642d9SDouglas Gilbert 		       sdebug_sector_size);
301044d92694SMartin K. Petersen 
30119ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
301244d92694SMartin K. Petersen 		map_region(lba, num);
301344d92694SMartin K. Petersen out:
301444d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
301544d92694SMartin K. Petersen 
301644d92694SMartin K. Petersen 	return 0;
301744d92694SMartin K. Petersen }
301844d92694SMartin K. Petersen 
3019fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp,
3020fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3021c2248fc9SDouglas Gilbert {
3022c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3023c2248fc9SDouglas Gilbert 	u32 lba;
3024c2248fc9SDouglas Gilbert 	u16 num;
3025c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3026c2248fc9SDouglas Gilbert 	bool unmap = false;
3027c2248fc9SDouglas Gilbert 
3028c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3029773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
3030c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3031c2248fc9SDouglas Gilbert 			return check_condition_result;
3032c2248fc9SDouglas Gilbert 		} else
3033c2248fc9SDouglas Gilbert 			unmap = true;
3034c2248fc9SDouglas Gilbert 	}
3035c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3036c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3037773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3038c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3039c2248fc9SDouglas Gilbert 		return check_condition_result;
3040c2248fc9SDouglas Gilbert 	}
3041c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3042c2248fc9SDouglas Gilbert }
3043c2248fc9SDouglas Gilbert 
3044fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp,
3045fd32119bSDouglas Gilbert 			      struct sdebug_dev_info *devip)
3046c2248fc9SDouglas Gilbert {
3047c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3048c2248fc9SDouglas Gilbert 	u64 lba;
3049c2248fc9SDouglas Gilbert 	u32 num;
3050c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3051c2248fc9SDouglas Gilbert 	bool unmap = false;
3052c2248fc9SDouglas Gilbert 	bool ndob = false;
3053c2248fc9SDouglas Gilbert 
3054c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3055773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
3056c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3057c2248fc9SDouglas Gilbert 			return check_condition_result;
3058c2248fc9SDouglas Gilbert 		} else
3059c2248fc9SDouglas Gilbert 			unmap = true;
3060c2248fc9SDouglas Gilbert 	}
3061c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3062c2248fc9SDouglas Gilbert 		ndob = true;
3063c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3064c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3065773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
3066c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3067c2248fc9SDouglas Gilbert 		return check_condition_result;
3068c2248fc9SDouglas Gilbert 	}
3069c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3070c2248fc9SDouglas Gilbert }
3071c2248fc9SDouglas Gilbert 
3072acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3073acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3074acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3075fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp,
3076fd32119bSDouglas Gilbert 			     struct sdebug_dev_info *devip)
3077acafd0b9SEwan D. Milne {
3078acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3079acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3080acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3081acafd0b9SEwan D. Milne 	u8 mode;
3082acafd0b9SEwan D. Milne 
3083acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3084acafd0b9SEwan D. Milne 	switch (mode) {
3085acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3086acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3087acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3088acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3089acafd0b9SEwan D. Milne 		break;
3090acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3091acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3092acafd0b9SEwan D. Milne 		break;
3093acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3094acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3095acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3096acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3097acafd0b9SEwan D. Milne 				    dev_list)
3098acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3099acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3100acafd0b9SEwan D. Milne 				if (devip != dp)
3101acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3102acafd0b9SEwan D. Milne 						dp->uas_bm);
3103acafd0b9SEwan D. Milne 			}
3104acafd0b9SEwan D. Milne 		break;
3105acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3106acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3107acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3108acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3109acafd0b9SEwan D. Milne 				    dev_list)
3110acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3111acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3112acafd0b9SEwan D. Milne 					dp->uas_bm);
3113acafd0b9SEwan D. Milne 		break;
3114acafd0b9SEwan D. Milne 	default:
3115acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3116acafd0b9SEwan D. Milne 		break;
3117acafd0b9SEwan D. Milne 	}
3118acafd0b9SEwan D. Milne 	return 0;
3119acafd0b9SEwan D. Milne }
3120acafd0b9SEwan D. Milne 
3121fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp,
3122fd32119bSDouglas Gilbert 			   struct sdebug_dev_info *devip)
312338d5c833SDouglas Gilbert {
312438d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
312538d5c833SDouglas Gilbert 	u8 *arr;
312638d5c833SDouglas Gilbert 	u8 *fake_storep_hold;
312738d5c833SDouglas Gilbert 	u64 lba;
312838d5c833SDouglas Gilbert 	u32 dnum;
3129773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
313038d5c833SDouglas Gilbert 	u8 num;
313138d5c833SDouglas Gilbert 	unsigned long iflags;
313238d5c833SDouglas Gilbert 	int ret;
3133d467d31fSDouglas Gilbert 	int retval = 0;
313438d5c833SDouglas Gilbert 
3135d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
313638d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
313738d5c833SDouglas Gilbert 	if (0 == num)
313838d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
31398475c811SChristoph Hellwig 	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
314038d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
314138d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
314238d5c833SDouglas Gilbert 		return check_condition_result;
314338d5c833SDouglas Gilbert 	}
31448475c811SChristoph Hellwig 	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
31458475c811SChristoph Hellwig 	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
314638d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
314738d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
314838d5c833SDouglas Gilbert 			    "to DIF device\n");
314938d5c833SDouglas Gilbert 
315038d5c833SDouglas Gilbert 	/* inline check_device_access_params() */
315138d5c833SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
315238d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
315338d5c833SDouglas Gilbert 		return check_condition_result;
315438d5c833SDouglas Gilbert 	}
315538d5c833SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
315638d5c833SDouglas Gilbert 	if (num > sdebug_store_sectors) {
315738d5c833SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
315838d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
315938d5c833SDouglas Gilbert 		return check_condition_result;
316038d5c833SDouglas Gilbert 	}
3161d467d31fSDouglas Gilbert 	dnum = 2 * num;
3162d467d31fSDouglas Gilbert 	arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3163d467d31fSDouglas Gilbert 	if (NULL == arr) {
3164d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3165d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3166d467d31fSDouglas Gilbert 		return check_condition_result;
3167d467d31fSDouglas Gilbert 	}
316838d5c833SDouglas Gilbert 
316938d5c833SDouglas Gilbert 	write_lock_irqsave(&atomic_rw, iflags);
317038d5c833SDouglas Gilbert 
317138d5c833SDouglas Gilbert 	/* trick do_device_access() to fetch both compare and write buffers
317238d5c833SDouglas Gilbert 	 * from data-in into arr. Safe (atomic) since write_lock held. */
317338d5c833SDouglas Gilbert 	fake_storep_hold = fake_storep;
317438d5c833SDouglas Gilbert 	fake_storep = arr;
317538d5c833SDouglas Gilbert 	ret = do_device_access(scp, 0, dnum, true);
317638d5c833SDouglas Gilbert 	fake_storep = fake_storep_hold;
317738d5c833SDouglas Gilbert 	if (ret == -1) {
3178d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3179d467d31fSDouglas Gilbert 		goto cleanup;
3180773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
318138d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
318238d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
318338d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
318438d5c833SDouglas Gilbert 	if (!comp_write_worker(lba, num, arr)) {
318538d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3186d467d31fSDouglas Gilbert 		retval = check_condition_result;
3187d467d31fSDouglas Gilbert 		goto cleanup;
318838d5c833SDouglas Gilbert 	}
318938d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
319038d5c833SDouglas Gilbert 		map_region(lba, num);
3191d467d31fSDouglas Gilbert cleanup:
319238d5c833SDouglas Gilbert 	write_unlock_irqrestore(&atomic_rw, iflags);
3193d467d31fSDouglas Gilbert 	kfree(arr);
3194d467d31fSDouglas Gilbert 	return retval;
319538d5c833SDouglas Gilbert }
319638d5c833SDouglas Gilbert 
319744d92694SMartin K. Petersen struct unmap_block_desc {
319844d92694SMartin K. Petersen 	__be64	lba;
319944d92694SMartin K. Petersen 	__be32	blocks;
320044d92694SMartin K. Petersen 	__be32	__reserved;
320144d92694SMartin K. Petersen };
320244d92694SMartin K. Petersen 
3203fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
320444d92694SMartin K. Petersen {
320544d92694SMartin K. Petersen 	unsigned char *buf;
320644d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
320744d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
320844d92694SMartin K. Petersen 	int ret;
32096c78cc06SAkinobu Mita 	unsigned long iflags;
321044d92694SMartin K. Petersen 
321144d92694SMartin K. Petersen 
3212c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3213c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3214c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3215c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
321644d92694SMartin K. Petersen 
321744d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3218773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3219c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
322044d92694SMartin K. Petersen 		return check_condition_result;
3221c2248fc9SDouglas Gilbert 	}
322244d92694SMartin K. Petersen 
3223b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3224c2248fc9SDouglas Gilbert 	if (!buf) {
3225c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3226c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3227c2248fc9SDouglas Gilbert 		return check_condition_result;
3228c2248fc9SDouglas Gilbert 	}
3229c2248fc9SDouglas Gilbert 
3230c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
323144d92694SMartin K. Petersen 
323244d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
323344d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
323444d92694SMartin K. Petersen 
323544d92694SMartin K. Petersen 	desc = (void *)&buf[8];
323644d92694SMartin K. Petersen 
32376c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
32386c78cc06SAkinobu Mita 
323944d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
324044d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
324144d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
324244d92694SMartin K. Petersen 
3243c2248fc9SDouglas Gilbert 		ret = check_device_access_params(scp, lba, num);
324444d92694SMartin K. Petersen 		if (ret)
324544d92694SMartin K. Petersen 			goto out;
324644d92694SMartin K. Petersen 
324744d92694SMartin K. Petersen 		unmap_region(lba, num);
324844d92694SMartin K. Petersen 	}
324944d92694SMartin K. Petersen 
325044d92694SMartin K. Petersen 	ret = 0;
325144d92694SMartin K. Petersen 
325244d92694SMartin K. Petersen out:
32536c78cc06SAkinobu Mita 	write_unlock_irqrestore(&atomic_rw, iflags);
325444d92694SMartin K. Petersen 	kfree(buf);
325544d92694SMartin K. Petersen 
325644d92694SMartin K. Petersen 	return ret;
325744d92694SMartin K. Petersen }
325844d92694SMartin K. Petersen 
325944d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
326044d92694SMartin K. Petersen 
3261fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp,
3262fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
326344d92694SMartin K. Petersen {
3264c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3265c2248fc9SDouglas Gilbert 	u64 lba;
3266c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
3267c2248fc9SDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
326844d92694SMartin K. Petersen 	int ret;
326944d92694SMartin K. Petersen 
3270c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3271c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
327244d92694SMartin K. Petersen 
327344d92694SMartin K. Petersen 	if (alloc_len < 24)
327444d92694SMartin K. Petersen 		return 0;
327544d92694SMartin K. Petersen 
3276c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, 1);
327744d92694SMartin K. Petersen 	if (ret)
327844d92694SMartin K. Petersen 		return ret;
327944d92694SMartin K. Petersen 
3280c2248fc9SDouglas Gilbert 	if (scsi_debug_lbp())
328144d92694SMartin K. Petersen 		mapped = map_state(lba, &num);
3282c2248fc9SDouglas Gilbert 	else {
3283c2248fc9SDouglas Gilbert 		mapped = 1;
3284c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
3285c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
3286c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
3287c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
3288c2248fc9SDouglas Gilbert 		else
3289c2248fc9SDouglas Gilbert 			num = 0xffffffff;
3290c2248fc9SDouglas Gilbert 	}
329144d92694SMartin K. Petersen 
329244d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
3293c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
3294c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
3295c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
3296c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
329744d92694SMartin K. Petersen 
3298c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
329944d92694SMartin K. Petersen }
330044d92694SMartin K. Petersen 
3301fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8
3302fb0cc8d1SDouglas Gilbert 
33038d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit"
33048d039e22SDouglas Gilbert  * (W-LUN), the normal Linux scanning logic does not associate it with a
33058d039e22SDouglas Gilbert  * device (e.g. /dev/sg7). The following magic will make that association:
33068d039e22SDouglas Gilbert  *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
33078d039e22SDouglas Gilbert  * where <n> is a host number. If there are multiple targets in a host then
33088d039e22SDouglas Gilbert  * the above will associate a W-LUN to each target. To only get a W-LUN
33098d039e22SDouglas Gilbert  * for target 2, then use "echo '- 2 49409' > scan" .
33108d039e22SDouglas Gilbert  */
33111da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp,
33121da177e4SLinus Torvalds 			    struct sdebug_dev_info *devip)
33131da177e4SLinus Torvalds {
331401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
33158d039e22SDouglas Gilbert 	unsigned int alloc_len;
33168d039e22SDouglas Gilbert 	unsigned char select_report;
33178d039e22SDouglas Gilbert 	u64 lun;
33188d039e22SDouglas Gilbert 	struct scsi_lun *lun_p;
3319fb0cc8d1SDouglas Gilbert 	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
33208d039e22SDouglas Gilbert 	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
33218d039e22SDouglas Gilbert 	unsigned int wlun_cnt;	/* report luns W-LUN count */
33228d039e22SDouglas Gilbert 	unsigned int tlun_cnt;	/* total LUN count */
33238d039e22SDouglas Gilbert 	unsigned int rlen;	/* response length (in bytes) */
3324fb0cc8d1SDouglas Gilbert 	int k, j, n, res;
3325fb0cc8d1SDouglas Gilbert 	unsigned int off_rsp = 0;
3326fb0cc8d1SDouglas Gilbert 	const int sz_lun = sizeof(struct scsi_lun);
33271da177e4SLinus Torvalds 
332819c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
33298d039e22SDouglas Gilbert 
33308d039e22SDouglas Gilbert 	select_report = cmd[2];
33318d039e22SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
33328d039e22SDouglas Gilbert 
33338d039e22SDouglas Gilbert 	if (alloc_len < 4) {
33348d039e22SDouglas Gilbert 		pr_err("alloc len too small %d\n", alloc_len);
33358d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
33361da177e4SLinus Torvalds 		return check_condition_result;
33371da177e4SLinus Torvalds 	}
33388d039e22SDouglas Gilbert 
33398d039e22SDouglas Gilbert 	switch (select_report) {
33408d039e22SDouglas Gilbert 	case 0:		/* all LUNs apart from W-LUNs */
3341773642d9SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
33428d039e22SDouglas Gilbert 		wlun_cnt = 0;
33438d039e22SDouglas Gilbert 		break;
33448d039e22SDouglas Gilbert 	case 1:		/* only W-LUNs */
3345c65b1445SDouglas Gilbert 		lun_cnt = 0;
33468d039e22SDouglas Gilbert 		wlun_cnt = 1;
33478d039e22SDouglas Gilbert 		break;
33488d039e22SDouglas Gilbert 	case 2:		/* all LUNs */
33498d039e22SDouglas Gilbert 		lun_cnt = sdebug_max_luns;
33508d039e22SDouglas Gilbert 		wlun_cnt = 1;
33518d039e22SDouglas Gilbert 		break;
33528d039e22SDouglas Gilbert 	case 0x10:	/* only administrative LUs */
33538d039e22SDouglas Gilbert 	case 0x11:	/* see SPC-5 */
33548d039e22SDouglas Gilbert 	case 0x12:	/* only subsiduary LUs owned by referenced LU */
33558d039e22SDouglas Gilbert 	default:
33568d039e22SDouglas Gilbert 		pr_debug("select report invalid %d\n", select_report);
33578d039e22SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
33588d039e22SDouglas Gilbert 		return check_condition_result;
33598d039e22SDouglas Gilbert 	}
33608d039e22SDouglas Gilbert 
33618d039e22SDouglas Gilbert 	if (sdebug_no_lun_0 && (lun_cnt > 0))
3362c65b1445SDouglas Gilbert 		--lun_cnt;
33638d039e22SDouglas Gilbert 
33648d039e22SDouglas Gilbert 	tlun_cnt = lun_cnt + wlun_cnt;
3365fb0cc8d1SDouglas Gilbert 	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
3366fb0cc8d1SDouglas Gilbert 	scsi_set_resid(scp, scsi_bufflen(scp));
33678d039e22SDouglas Gilbert 	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
33688d039e22SDouglas Gilbert 		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
33698d039e22SDouglas Gilbert 
3370fb0cc8d1SDouglas Gilbert 	/* loops rely on sizeof response header same as sizeof lun (both 8) */
33718d039e22SDouglas Gilbert 	lun = sdebug_no_lun_0 ? 1 : 0;
3372fb0cc8d1SDouglas Gilbert 	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3373fb0cc8d1SDouglas Gilbert 		memset(arr, 0, sizeof(arr));
3374fb0cc8d1SDouglas Gilbert 		lun_p = (struct scsi_lun *)&arr[0];
3375fb0cc8d1SDouglas Gilbert 		if (k == 0) {
3376fb0cc8d1SDouglas Gilbert 			put_unaligned_be32(rlen, &arr[0]);
3377fb0cc8d1SDouglas Gilbert 			++lun_p;
3378fb0cc8d1SDouglas Gilbert 			j = 1;
3379fb0cc8d1SDouglas Gilbert 		}
3380fb0cc8d1SDouglas Gilbert 		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3381fb0cc8d1SDouglas Gilbert 			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3382fb0cc8d1SDouglas Gilbert 				break;
3383fb0cc8d1SDouglas Gilbert 			int_to_scsilun(lun++, lun_p);
3384fb0cc8d1SDouglas Gilbert 		}
3385fb0cc8d1SDouglas Gilbert 		if (j < RL_BUCKET_ELEMS)
3386fb0cc8d1SDouglas Gilbert 			break;
3387fb0cc8d1SDouglas Gilbert 		n = j * sz_lun;
3388fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3389fb0cc8d1SDouglas Gilbert 		if (res)
3390fb0cc8d1SDouglas Gilbert 			return res;
3391fb0cc8d1SDouglas Gilbert 		off_rsp += n;
3392fb0cc8d1SDouglas Gilbert 	}
3393fb0cc8d1SDouglas Gilbert 	if (wlun_cnt) {
3394fb0cc8d1SDouglas Gilbert 		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3395fb0cc8d1SDouglas Gilbert 		++j;
3396fb0cc8d1SDouglas Gilbert 	}
3397fb0cc8d1SDouglas Gilbert 	if (j > 0)
3398fb0cc8d1SDouglas Gilbert 		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
33998d039e22SDouglas Gilbert 	return res;
34001da177e4SLinus Torvalds }
34011da177e4SLinus Torvalds 
3402c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3403c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
3404c639d14eSFUJITA Tomonori {
3405be4e11beSAkinobu Mita 	int j;
3406c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
3407c639d14eSFUJITA Tomonori 	unsigned int offset;
3408c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
3409be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3410c639d14eSFUJITA Tomonori 
3411c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
3412b333a819SDouglas Gilbert 	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
3413c5af0db9SAkinobu Mita 	if (!buf) {
341422017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
341522017ed2SDouglas Gilbert 				INSUFF_RES_ASCQ);
3416c5af0db9SAkinobu Mita 		return check_condition_result;
3417c5af0db9SAkinobu Mita 	}
3418c639d14eSFUJITA Tomonori 
341921a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
3420c639d14eSFUJITA Tomonori 
3421c639d14eSFUJITA Tomonori 	offset = 0;
3422be4e11beSAkinobu Mita 	sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3423be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_TO_SG);
3424c639d14eSFUJITA Tomonori 
3425be4e11beSAkinobu Mita 	while (sg_miter_next(&miter)) {
3426be4e11beSAkinobu Mita 		kaddr = miter.addr;
3427be4e11beSAkinobu Mita 		for (j = 0; j < miter.length; j++)
3428be4e11beSAkinobu Mita 			*(kaddr + j) ^= *(buf + offset + j);
3429c639d14eSFUJITA Tomonori 
3430be4e11beSAkinobu Mita 		offset += miter.length;
3431c639d14eSFUJITA Tomonori 	}
3432be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3433c639d14eSFUJITA Tomonori 	kfree(buf);
3434c639d14eSFUJITA Tomonori 
3435be4e11beSAkinobu Mita 	return 0;
3436c639d14eSFUJITA Tomonori }
3437c639d14eSFUJITA Tomonori 
3438fd32119bSDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3439fd32119bSDouglas Gilbert 			       struct sdebug_dev_info *devip)
3440c2248fc9SDouglas Gilbert {
3441c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3442c2248fc9SDouglas Gilbert 	u64 lba;
3443c2248fc9SDouglas Gilbert 	u32 num;
3444c2248fc9SDouglas Gilbert 	int errsts;
3445c2248fc9SDouglas Gilbert 
3446c2248fc9SDouglas Gilbert 	if (!scsi_bidi_cmnd(scp)) {
3447c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3448c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3449c2248fc9SDouglas Gilbert 		return check_condition_result;
3450c2248fc9SDouglas Gilbert 	}
3451c2248fc9SDouglas Gilbert 	errsts = resp_read_dt0(scp, devip);
3452c2248fc9SDouglas Gilbert 	if (errsts)
3453c2248fc9SDouglas Gilbert 		return errsts;
3454c2248fc9SDouglas Gilbert 	if (!(cmd[1] & 0x4)) {		/* DISABLE_WRITE is not set */
3455c2248fc9SDouglas Gilbert 		errsts = resp_write_dt0(scp, devip);
3456c2248fc9SDouglas Gilbert 		if (errsts)
3457c2248fc9SDouglas Gilbert 			return errsts;
3458c2248fc9SDouglas Gilbert 	}
3459c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3460c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3461c2248fc9SDouglas Gilbert 	return resp_xdwriteread(scp, lba, num, devip);
3462c2248fc9SDouglas Gilbert }
3463c2248fc9SDouglas Gilbert 
3464c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3465c4837394SDouglas Gilbert {
3466c4837394SDouglas Gilbert 	struct sdebug_queue *sqp = sdebug_q_arr;
3467c4837394SDouglas Gilbert 
3468c4837394SDouglas Gilbert 	if (sdebug_mq_active) {
3469c4837394SDouglas Gilbert 		u32 tag = blk_mq_unique_tag(cmnd->request);
3470c4837394SDouglas Gilbert 		u16 hwq = blk_mq_unique_tag_to_hwq(tag);
3471c4837394SDouglas Gilbert 
3472c4837394SDouglas Gilbert 		if (unlikely(hwq >= submit_queues)) {
3473c4837394SDouglas Gilbert 			pr_warn("Unexpected hwq=%d, apply modulo\n", hwq);
3474c4837394SDouglas Gilbert 			hwq %= submit_queues;
3475c4837394SDouglas Gilbert 		}
3476c4837394SDouglas Gilbert 		pr_debug("tag=%u, hwq=%d\n", tag, hwq);
3477c4837394SDouglas Gilbert 		return sqp + hwq;
3478c4837394SDouglas Gilbert 	} else
3479c4837394SDouglas Gilbert 		return sqp;
3480c4837394SDouglas Gilbert }
3481c4837394SDouglas Gilbert 
3482c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */
3483fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
34841da177e4SLinus Torvalds {
3485c4837394SDouglas Gilbert 	int qc_idx;
3486cbf67842SDouglas Gilbert 	int retiring = 0;
34871da177e4SLinus Torvalds 	unsigned long iflags;
3488c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3489cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3490cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
3491cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
34921da177e4SLinus Torvalds 
3493c4837394SDouglas Gilbert 	qc_idx = sd_dp->qc_idx;
3494c4837394SDouglas Gilbert 	sqp = sdebug_q_arr + sd_dp->sqa_idx;
3495c4837394SDouglas Gilbert 	if (sdebug_statistics) {
3496cbf67842SDouglas Gilbert 		atomic_inc(&sdebug_completions);
3497c4837394SDouglas Gilbert 		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3498c4837394SDouglas Gilbert 			atomic_inc(&sdebug_miss_cpus);
3499c4837394SDouglas Gilbert 	}
3500c4837394SDouglas Gilbert 	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3501c4837394SDouglas Gilbert 		pr_err("wild qc_idx=%d\n", qc_idx);
35021da177e4SLinus Torvalds 		return;
35031da177e4SLinus Torvalds 	}
3504c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
3505c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[qc_idx];
3506cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
3507b01f6f83SDouglas Gilbert 	if (unlikely(scp == NULL)) {
3508c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3509c4837394SDouglas Gilbert 		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3510c4837394SDouglas Gilbert 		       sd_dp->sqa_idx, qc_idx);
35111da177e4SLinus Torvalds 		return;
35121da177e4SLinus Torvalds 	}
3513cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
3514f46eb0e9SDouglas Gilbert 	if (likely(devip))
3515cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
3516cbf67842SDouglas Gilbert 	else
3517c1287970STomas Winkler 		pr_err("devip=NULL\n");
3518f46eb0e9SDouglas Gilbert 	if (unlikely(atomic_read(&retired_max_queue) > 0))
3519cbf67842SDouglas Gilbert 		retiring = 1;
3520cbf67842SDouglas Gilbert 
3521cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
3522c4837394SDouglas Gilbert 	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3523c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3524c1287970STomas Winkler 		pr_err("Unexpected completion\n");
3525cbf67842SDouglas Gilbert 		return;
35261da177e4SLinus Torvalds 	}
35271da177e4SLinus Torvalds 
3528cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
3529cbf67842SDouglas Gilbert 		int k, retval;
3530cbf67842SDouglas Gilbert 
3531cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
3532c4837394SDouglas Gilbert 		if (qc_idx >= retval) {
3533c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3534c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
3535cbf67842SDouglas Gilbert 			return;
3536cbf67842SDouglas Gilbert 		}
3537c4837394SDouglas Gilbert 		k = find_last_bit(sqp->in_use_bm, retval);
3538773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
3539cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3540cbf67842SDouglas Gilbert 		else
3541cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
3542cbf67842SDouglas Gilbert 	}
3543c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3544cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
3545cbf67842SDouglas Gilbert }
3546cbf67842SDouglas Gilbert 
3547cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
3548fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
3549cbf67842SDouglas Gilbert {
3550a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3551a10bc12aSDouglas Gilbert 						  hrt);
3552a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3553cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
3554cbf67842SDouglas Gilbert }
35551da177e4SLinus Torvalds 
3556a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */
3557fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work)
3558a10bc12aSDouglas Gilbert {
3559a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3560a10bc12aSDouglas Gilbert 						  ew.work);
3561a10bc12aSDouglas Gilbert 	sdebug_q_cmd_complete(sd_dp);
3562a10bc12aSDouglas Gilbert }
3563a10bc12aSDouglas Gilbert 
356409ba24c1SDouglas Gilbert static bool got_shared_uuid;
356509ba24c1SDouglas Gilbert static uuid_be shared_uuid;
356609ba24c1SDouglas Gilbert 
3567fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create(
3568fd32119bSDouglas Gilbert 			struct sdebug_host_info *sdbg_host, gfp_t flags)
35695cb2fc06SFUJITA Tomonori {
35705cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
35715cb2fc06SFUJITA Tomonori 
35725cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
35735cb2fc06SFUJITA Tomonori 	if (devip) {
357409ba24c1SDouglas Gilbert 		if (sdebug_uuid_ctl == 1)
357509ba24c1SDouglas Gilbert 			uuid_be_gen(&devip->lu_name);
357609ba24c1SDouglas Gilbert 		else if (sdebug_uuid_ctl == 2) {
357709ba24c1SDouglas Gilbert 			if (got_shared_uuid)
357809ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
357909ba24c1SDouglas Gilbert 			else {
358009ba24c1SDouglas Gilbert 				uuid_be_gen(&shared_uuid);
358109ba24c1SDouglas Gilbert 				got_shared_uuid = true;
358209ba24c1SDouglas Gilbert 				devip->lu_name = shared_uuid;
358309ba24c1SDouglas Gilbert 			}
358409ba24c1SDouglas Gilbert 		}
35855cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
35865cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
35875cb2fc06SFUJITA Tomonori 	}
35885cb2fc06SFUJITA Tomonori 	return devip;
35895cb2fc06SFUJITA Tomonori }
35905cb2fc06SFUJITA Tomonori 
3591f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
35921da177e4SLinus Torvalds {
35931da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
35941da177e4SLinus Torvalds 	struct sdebug_dev_info *open_devip = NULL;
3595f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip;
35961da177e4SLinus Torvalds 
3597d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
35981da177e4SLinus Torvalds 	if (!sdbg_host) {
3599c1287970STomas Winkler 		pr_err("Host info NULL\n");
36001da177e4SLinus Torvalds 		return NULL;
36011da177e4SLinus Torvalds         }
36021da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
36031da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
36041da177e4SLinus Torvalds                     (devip->target == sdev->id) &&
36051da177e4SLinus Torvalds                     (devip->lun == sdev->lun))
36061da177e4SLinus Torvalds                         return devip;
36071da177e4SLinus Torvalds 		else {
36081da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
36091da177e4SLinus Torvalds 				open_devip = devip;
36101da177e4SLinus Torvalds 		}
36111da177e4SLinus Torvalds 	}
36125cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
36135cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
36145cb2fc06SFUJITA Tomonori 		if (!open_devip) {
3615c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
36161da177e4SLinus Torvalds 			return NULL;
36171da177e4SLinus Torvalds 		}
36181da177e4SLinus Torvalds 	}
3619a75869d1SFUJITA Tomonori 
36201da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
36211da177e4SLinus Torvalds 	open_devip->target = sdev->id;
36221da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
36231da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
3624cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
3625cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
3626c2248fc9SDouglas Gilbert 	open_devip->used = true;
36271da177e4SLinus Torvalds 	return open_devip;
36281da177e4SLinus Torvalds }
36291da177e4SLinus Torvalds 
36308dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
36311da177e4SLinus Torvalds {
3632773642d9SDouglas Gilbert 	if (sdebug_verbose)
3633c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
36348dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
363575ad23bcSNick Piggin 	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
36368dea0d02SFUJITA Tomonori 	return 0;
36378dea0d02SFUJITA Tomonori }
36381da177e4SLinus Torvalds 
36398dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
36408dea0d02SFUJITA Tomonori {
3641f46eb0e9SDouglas Gilbert 	struct sdebug_dev_info *devip =
3642f46eb0e9SDouglas Gilbert 			(struct sdebug_dev_info *)sdp->hostdata;
3643a34c4e98SFUJITA Tomonori 
3644773642d9SDouglas Gilbert 	if (sdebug_verbose)
3645c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
36468dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3647b01f6f83SDouglas Gilbert 	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3648b01f6f83SDouglas Gilbert 		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3649b01f6f83SDouglas Gilbert 	if (devip == NULL) {
3650f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
3651b01f6f83SDouglas Gilbert 		if (devip == NULL)
36528dea0d02SFUJITA Tomonori 			return 1;  /* no resources, will be marked offline */
3653f46eb0e9SDouglas Gilbert 	}
3654c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
36556bb5e6e7SAkinobu Mita 	blk_queue_max_segment_size(sdp->request_queue, -1U);
3656773642d9SDouglas Gilbert 	if (sdebug_no_uld)
365778d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
36588dea0d02SFUJITA Tomonori 	return 0;
36598dea0d02SFUJITA Tomonori }
36608dea0d02SFUJITA Tomonori 
36618dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
36628dea0d02SFUJITA Tomonori {
36638dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
36648dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
36658dea0d02SFUJITA Tomonori 
3666773642d9SDouglas Gilbert 	if (sdebug_verbose)
3667c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
36688dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
36698dea0d02SFUJITA Tomonori 	if (devip) {
367025985edcSLucas De Marchi 		/* make this slot available for re-use */
3671c2248fc9SDouglas Gilbert 		devip->used = false;
36728dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
36738dea0d02SFUJITA Tomonori 	}
36748dea0d02SFUJITA Tomonori }
36758dea0d02SFUJITA Tomonori 
3676c4837394SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp)
3677c4837394SDouglas Gilbert {
3678c4837394SDouglas Gilbert 	if (!sd_dp)
3679c4837394SDouglas Gilbert 		return;
3680c4837394SDouglas Gilbert 	if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0))
3681c4837394SDouglas Gilbert 		hrtimer_cancel(&sd_dp->hrt);
3682c4837394SDouglas Gilbert 	else if (sdebug_jdelay < 0)
3683c4837394SDouglas Gilbert 		cancel_work_sync(&sd_dp->ew.work);
3684c4837394SDouglas Gilbert }
3685c4837394SDouglas Gilbert 
3686a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else
3687a10bc12aSDouglas Gilbert    returns false */
3688a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
36898dea0d02SFUJITA Tomonori {
36908dea0d02SFUJITA Tomonori 	unsigned long iflags;
3691c4837394SDouglas Gilbert 	int j, k, qmax, r_qmax;
3692c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
36938dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3694cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3695a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
36968dea0d02SFUJITA Tomonori 
3697c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3698c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
3699773642d9SDouglas Gilbert 		qmax = sdebug_max_queue;
3700cbf67842SDouglas Gilbert 		r_qmax = atomic_read(&retired_max_queue);
3701cbf67842SDouglas Gilbert 		if (r_qmax > qmax)
3702cbf67842SDouglas Gilbert 			qmax = r_qmax;
3703cbf67842SDouglas Gilbert 		for (k = 0; k < qmax; ++k) {
3704c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
3705c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
3706a10bc12aSDouglas Gilbert 				if (cmnd != sqcp->a_cmnd)
3707a10bc12aSDouglas Gilbert 					continue;
3708c4837394SDouglas Gilbert 				/* found */
3709db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3710db525fceSDouglas Gilbert 						cmnd->device->hostdata;
3711db525fceSDouglas Gilbert 				if (devip)
3712db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3713db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3714a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
3715c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3716c4837394SDouglas Gilbert 				stop_qc_helper(sd_dp);
3717c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
3718a10bc12aSDouglas Gilbert 				return true;
37198dea0d02SFUJITA Tomonori 			}
3720cbf67842SDouglas Gilbert 		}
3721c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3722c4837394SDouglas Gilbert 	}
3723a10bc12aSDouglas Gilbert 	return false;
37248dea0d02SFUJITA Tomonori }
37258dea0d02SFUJITA Tomonori 
3726a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */
37278dea0d02SFUJITA Tomonori static void stop_all_queued(void)
37288dea0d02SFUJITA Tomonori {
37298dea0d02SFUJITA Tomonori 	unsigned long iflags;
3730c4837394SDouglas Gilbert 	int j, k;
3731c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
37328dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3733cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3734a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
37358dea0d02SFUJITA Tomonori 
3736c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3737c4837394SDouglas Gilbert 		spin_lock_irqsave(&sqp->qc_lock, iflags);
3738c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3739c4837394SDouglas Gilbert 			if (test_bit(k, sqp->in_use_bm)) {
3740c4837394SDouglas Gilbert 				sqcp = &sqp->qc_arr[k];
3741c4837394SDouglas Gilbert 				if (sqcp->a_cmnd == NULL)
3742a10bc12aSDouglas Gilbert 					continue;
3743db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3744db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
3745db525fceSDouglas Gilbert 				if (devip)
3746db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3747db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3748a10bc12aSDouglas Gilbert 				sd_dp = sqcp->sd_dp;
3749c4837394SDouglas Gilbert 				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3750c4837394SDouglas Gilbert 				stop_qc_helper(sd_dp);
3751c4837394SDouglas Gilbert 				clear_bit(k, sqp->in_use_bm);
3752c4837394SDouglas Gilbert 				spin_lock_irqsave(&sqp->qc_lock, iflags);
37538dea0d02SFUJITA Tomonori 			}
37548dea0d02SFUJITA Tomonori 		}
3755c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3756c4837394SDouglas Gilbert 	}
3757cbf67842SDouglas Gilbert }
3758cbf67842SDouglas Gilbert 
3759cbf67842SDouglas Gilbert /* Free queued command memory on heap */
3760cbf67842SDouglas Gilbert static void free_all_queued(void)
3761cbf67842SDouglas Gilbert {
3762c4837394SDouglas Gilbert 	int j, k;
3763c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3764cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3765cbf67842SDouglas Gilbert 
3766c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3767c4837394SDouglas Gilbert 		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3768c4837394SDouglas Gilbert 			sqcp = &sqp->qc_arr[k];
3769a10bc12aSDouglas Gilbert 			kfree(sqcp->sd_dp);
3770a10bc12aSDouglas Gilbert 			sqcp->sd_dp = NULL;
3771cbf67842SDouglas Gilbert 		}
37721da177e4SLinus Torvalds 	}
3773c4837394SDouglas Gilbert }
37741da177e4SLinus Torvalds 
37751da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
37761da177e4SLinus Torvalds {
3777a10bc12aSDouglas Gilbert 	bool ok;
3778a10bc12aSDouglas Gilbert 
37791da177e4SLinus Torvalds 	++num_aborts;
3780cbf67842SDouglas Gilbert 	if (SCpnt) {
3781a10bc12aSDouglas Gilbert 		ok = stop_queued_cmnd(SCpnt);
3782a10bc12aSDouglas Gilbert 		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3783a10bc12aSDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
3784a10bc12aSDouglas Gilbert 				    "%s: command%s found\n", __func__,
3785a10bc12aSDouglas Gilbert 				    ok ? "" : " not");
3786cbf67842SDouglas Gilbert 	}
37871da177e4SLinus Torvalds 	return SUCCESS;
37881da177e4SLinus Torvalds }
37891da177e4SLinus Torvalds 
37901da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
37911da177e4SLinus Torvalds {
37921da177e4SLinus Torvalds 	++num_dev_resets;
3793cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
3794cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
3795f46eb0e9SDouglas Gilbert 		struct sdebug_dev_info *devip =
3796f46eb0e9SDouglas Gilbert 				(struct sdebug_dev_info *)sdp->hostdata;
3797cbf67842SDouglas Gilbert 
3798773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3799cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
38001da177e4SLinus Torvalds 		if (devip)
3801cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
38021da177e4SLinus Torvalds 	}
38031da177e4SLinus Torvalds 	return SUCCESS;
38041da177e4SLinus Torvalds }
38051da177e4SLinus Torvalds 
3806cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3807cbf67842SDouglas Gilbert {
3808cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
3809cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3810cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
3811cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
3812cbf67842SDouglas Gilbert 	int k = 0;
3813cbf67842SDouglas Gilbert 
3814cbf67842SDouglas Gilbert 	++num_target_resets;
3815cbf67842SDouglas Gilbert 	if (!SCpnt)
3816cbf67842SDouglas Gilbert 		goto lie;
3817cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
3818cbf67842SDouglas Gilbert 	if (!sdp)
3819cbf67842SDouglas Gilbert 		goto lie;
3820773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3821cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3822cbf67842SDouglas Gilbert 	hp = sdp->host;
3823cbf67842SDouglas Gilbert 	if (!hp)
3824cbf67842SDouglas Gilbert 		goto lie;
3825cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3826cbf67842SDouglas Gilbert 	if (sdbg_host) {
3827cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
3828cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
3829cbf67842SDouglas Gilbert 				    dev_list)
3830cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
3831cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3832cbf67842SDouglas Gilbert 				++k;
3833cbf67842SDouglas Gilbert 			}
3834cbf67842SDouglas Gilbert 	}
3835773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3836cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3837cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
3838cbf67842SDouglas Gilbert lie:
3839cbf67842SDouglas Gilbert 	return SUCCESS;
3840cbf67842SDouglas Gilbert }
3841cbf67842SDouglas Gilbert 
38421da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
38431da177e4SLinus Torvalds {
38441da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
3845cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
38461da177e4SLinus Torvalds         struct scsi_device * sdp;
38471da177e4SLinus Torvalds         struct Scsi_Host * hp;
3848cbf67842SDouglas Gilbert 	int k = 0;
38491da177e4SLinus Torvalds 
38501da177e4SLinus Torvalds 	++num_bus_resets;
3851cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
3852cbf67842SDouglas Gilbert 		goto lie;
3853cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
3854773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3855cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3856cbf67842SDouglas Gilbert 	hp = sdp->host;
3857cbf67842SDouglas Gilbert 	if (hp) {
3858d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
38591da177e4SLinus Torvalds 		if (sdbg_host) {
3860cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
38611da177e4SLinus Torvalds                                             &sdbg_host->dev_info_list,
3862cbf67842SDouglas Gilbert 					    dev_list) {
3863cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3864cbf67842SDouglas Gilbert 				++k;
38651da177e4SLinus Torvalds 			}
38661da177e4SLinus Torvalds 		}
3867cbf67842SDouglas Gilbert 	}
3868773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3869cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3870cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
3871cbf67842SDouglas Gilbert lie:
38721da177e4SLinus Torvalds 	return SUCCESS;
38731da177e4SLinus Torvalds }
38741da177e4SLinus Torvalds 
38751da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
38761da177e4SLinus Torvalds {
38771da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
3878cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3879cbf67842SDouglas Gilbert 	int k = 0;
38801da177e4SLinus Torvalds 
38811da177e4SLinus Torvalds 	++num_host_resets;
3882773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3883cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
38841da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
38851da177e4SLinus Torvalds         list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3886cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
3887cbf67842SDouglas Gilbert 				    dev_list) {
3888cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3889cbf67842SDouglas Gilbert 			++k;
3890cbf67842SDouglas Gilbert 		}
38911da177e4SLinus Torvalds         }
38921da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
38931da177e4SLinus Torvalds 	stop_all_queued();
3894773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3895cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
3896cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
38971da177e4SLinus Torvalds 	return SUCCESS;
38981da177e4SLinus Torvalds }
38991da177e4SLinus Torvalds 
3900f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
39015f2578e5SFUJITA Tomonori 				      unsigned long store_size)
39021da177e4SLinus Torvalds {
39031da177e4SLinus Torvalds 	struct partition * pp;
39041da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
39051da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
39061da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
39071da177e4SLinus Torvalds 
39081da177e4SLinus Torvalds 	/* assume partition table already zeroed */
3909773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
39101da177e4SLinus Torvalds 		return;
3911773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
3912773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
3913c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
39141da177e4SLinus Torvalds 	}
3915c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
39161da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
3917773642d9SDouglas Gilbert 			   / sdebug_num_parts;
39181da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
39191da177e4SLinus Torvalds         starts[0] = sdebug_sectors_per;
3920773642d9SDouglas Gilbert 	for (k = 1; k < sdebug_num_parts; ++k)
39211da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
39221da177e4SLinus Torvalds 			    * heads_by_sects;
3923773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
3924773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
39251da177e4SLinus Torvalds 
39261da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
39271da177e4SLinus Torvalds 	ramp[511] = 0xAA;
39281da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
39291da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
39301da177e4SLinus Torvalds 		start_sec = starts[k];
39311da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
39321da177e4SLinus Torvalds 		pp->boot_ind = 0;
39331da177e4SLinus Torvalds 
39341da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
39351da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
39361da177e4SLinus Torvalds 			   / sdebug_sectors_per;
39371da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
39381da177e4SLinus Torvalds 
39391da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
39401da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
39411da177e4SLinus Torvalds 			       / sdebug_sectors_per;
39421da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
39431da177e4SLinus Torvalds 
3944150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
3945150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
39461da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
39471da177e4SLinus Torvalds 	}
39481da177e4SLinus Torvalds }
39491da177e4SLinus Torvalds 
3950c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block)
3951c4837394SDouglas Gilbert {
3952c4837394SDouglas Gilbert 	int j;
3953c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
3954c4837394SDouglas Gilbert 
3955c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
3956c4837394SDouglas Gilbert 		atomic_set(&sqp->blocked, (int)block);
3957c4837394SDouglas Gilbert }
3958c4837394SDouglas Gilbert 
3959c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
3960c4837394SDouglas Gilbert  * commands will be processed normally before triggers occur.
3961c4837394SDouglas Gilbert  */
3962c4837394SDouglas Gilbert static void tweak_cmnd_count(void)
3963c4837394SDouglas Gilbert {
3964c4837394SDouglas Gilbert 	int count, modulo;
3965c4837394SDouglas Gilbert 
3966c4837394SDouglas Gilbert 	modulo = abs(sdebug_every_nth);
3967c4837394SDouglas Gilbert 	if (modulo < 2)
3968c4837394SDouglas Gilbert 		return;
3969c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
3970c4837394SDouglas Gilbert 	count = atomic_read(&sdebug_cmnd_count);
3971c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
3972c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
3973c4837394SDouglas Gilbert }
3974c4837394SDouglas Gilbert 
3975c4837394SDouglas Gilbert static void clear_queue_stats(void)
3976c4837394SDouglas Gilbert {
3977c4837394SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
3978c4837394SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
3979c4837394SDouglas Gilbert 	atomic_set(&sdebug_miss_cpus, 0);
3980c4837394SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
3981c4837394SDouglas Gilbert }
3982c4837394SDouglas Gilbert 
3983c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp,
3984c4837394SDouglas Gilbert 			 struct sdebug_queued_cmd *sqcp)
3985c4837394SDouglas Gilbert {
3986c4837394SDouglas Gilbert 	if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0)
3987c4837394SDouglas Gilbert 		return;
3988c4837394SDouglas Gilbert 	sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
3989c4837394SDouglas Gilbert 	sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
3990c4837394SDouglas Gilbert 	sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
3991c4837394SDouglas Gilbert 	sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
3992c4837394SDouglas Gilbert 	sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
3993c4837394SDouglas Gilbert }
3994c4837394SDouglas Gilbert 
3995c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this
3996c4837394SDouglas Gilbert  * driver. It either completes the command by calling cmnd_done() or
3997c4837394SDouglas Gilbert  * schedules a hr timer or work queue then returns 0. Returns
3998c4837394SDouglas Gilbert  * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
3999c4837394SDouglas Gilbert  */
4000fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
4001cbf67842SDouglas Gilbert 			 int scsi_result, int delta_jiff)
40021da177e4SLinus Torvalds {
4003cbf67842SDouglas Gilbert 	unsigned long iflags;
4004cd62b7daSDouglas Gilbert 	int k, num_in_q, qdepth, inject;
4005c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4006c4837394SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
4007299b6c07STomas Winkler 	struct scsi_device *sdp;
4008a10bc12aSDouglas Gilbert 	struct sdebug_defer *sd_dp;
40091da177e4SLinus Torvalds 
4010b01f6f83SDouglas Gilbert 	if (unlikely(devip == NULL)) {
4011b01f6f83SDouglas Gilbert 		if (scsi_result == 0)
4012f46eb0e9SDouglas Gilbert 			scsi_result = DID_NO_CONNECT << 16;
4013f46eb0e9SDouglas Gilbert 		goto respond_in_thread;
40141da177e4SLinus Torvalds 	}
4015299b6c07STomas Winkler 	sdp = cmnd->device;
4016299b6c07STomas Winkler 
4017f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose && scsi_result))
4018cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4019cbf67842SDouglas Gilbert 			    __func__, scsi_result);
4020cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
4021cd62b7daSDouglas Gilbert 		goto respond_in_thread;
40221da177e4SLinus Torvalds 
4023cd62b7daSDouglas Gilbert 	/* schedule the response at a later time if resources permit */
4024c4837394SDouglas Gilbert 	sqp = get_queue(cmnd);
4025c4837394SDouglas Gilbert 	spin_lock_irqsave(&sqp->qc_lock, iflags);
4026c4837394SDouglas Gilbert 	if (unlikely(atomic_read(&sqp->blocked))) {
4027c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4028c4837394SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
4029c4837394SDouglas Gilbert 	}
4030cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
4031cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
4032cbf67842SDouglas Gilbert 	inject = 0;
4033f46eb0e9SDouglas Gilbert 	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
4034cd62b7daSDouglas Gilbert 		if (scsi_result) {
4035c4837394SDouglas Gilbert 			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4036cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4037cd62b7daSDouglas Gilbert 		} else
4038cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4039c4837394SDouglas Gilbert 	} else if (unlikely(sdebug_every_nth &&
4040773642d9SDouglas Gilbert 			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4041f46eb0e9SDouglas Gilbert 			    (scsi_result == 0))) {
4042cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
4043cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
4044773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
4045cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
4046cbf67842SDouglas Gilbert 			inject = 1;
4047cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
40481da177e4SLinus Torvalds 		}
4049cbf67842SDouglas Gilbert 	}
4050cbf67842SDouglas Gilbert 
4051c4837394SDouglas Gilbert 	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
4052f46eb0e9SDouglas Gilbert 	if (unlikely(k >= sdebug_max_queue)) {
4053c4837394SDouglas Gilbert 		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4054cd62b7daSDouglas Gilbert 		if (scsi_result)
4055cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4056773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
4057cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
4058773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
4059cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
4060cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
4061773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
4062cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
4063cbf67842SDouglas Gilbert 						    "report: host busy"));
4064cd62b7daSDouglas Gilbert 		if (scsi_result)
4065cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4066cd62b7daSDouglas Gilbert 		else
4067cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
40681da177e4SLinus Torvalds 	}
4069c4837394SDouglas Gilbert 	__set_bit(k, sqp->in_use_bm);
4070cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
4071c4837394SDouglas Gilbert 	sqcp = &sqp->qc_arr[k];
40721da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
4073c4837394SDouglas Gilbert 	cmnd->host_scribble = (unsigned char *)sqcp;
4074cbf67842SDouglas Gilbert 	cmnd->result = scsi_result;
4075a10bc12aSDouglas Gilbert 	sd_dp = sqcp->sd_dp;
4076c4837394SDouglas Gilbert 	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4077c4837394SDouglas Gilbert 	if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4078c4837394SDouglas Gilbert 		setup_inject(sqp, sqcp);
4079b01f6f83SDouglas Gilbert 	if (delta_jiff > 0 || sdebug_ndelay > 0) {
4080b333a819SDouglas Gilbert 		ktime_t kt;
4081cbf67842SDouglas Gilbert 
4082b333a819SDouglas Gilbert 		if (delta_jiff > 0) {
4083b333a819SDouglas Gilbert 			struct timespec ts;
4084b333a819SDouglas Gilbert 
4085b333a819SDouglas Gilbert 			jiffies_to_timespec(delta_jiff, &ts);
4086b333a819SDouglas Gilbert 			kt = ktime_set(ts.tv_sec, ts.tv_nsec);
4087b333a819SDouglas Gilbert 		} else
40888b0e1953SThomas Gleixner 			kt = sdebug_ndelay;
4089a10bc12aSDouglas Gilbert 		if (NULL == sd_dp) {
4090a10bc12aSDouglas Gilbert 			sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
4091a10bc12aSDouglas Gilbert 			if (NULL == sd_dp)
4092cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
4093a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4094a10bc12aSDouglas Gilbert 			hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
4095c4837394SDouglas Gilbert 				     HRTIMER_MODE_REL_PINNED);
4096a10bc12aSDouglas Gilbert 			sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
4097c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4098c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4099cbf67842SDouglas Gilbert 		}
4100c4837394SDouglas Gilbert 		if (sdebug_statistics)
4101c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
4102c4837394SDouglas Gilbert 		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4103c4837394SDouglas Gilbert 	} else {	/* jdelay < 0, use work queue */
4104a10bc12aSDouglas Gilbert 		if (NULL == sd_dp) {
4105a10bc12aSDouglas Gilbert 			sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC);
4106a10bc12aSDouglas Gilbert 			if (NULL == sd_dp)
4107cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
4108a10bc12aSDouglas Gilbert 			sqcp->sd_dp = sd_dp;
4109c4837394SDouglas Gilbert 			sd_dp->sqa_idx = sqp - sdebug_q_arr;
4110c4837394SDouglas Gilbert 			sd_dp->qc_idx = k;
4111a10bc12aSDouglas Gilbert 			INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
4112cbf67842SDouglas Gilbert 		}
4113c4837394SDouglas Gilbert 		if (sdebug_statistics)
4114c4837394SDouglas Gilbert 			sd_dp->issuing_cpu = raw_smp_processor_id();
4115a10bc12aSDouglas Gilbert 		schedule_work(&sd_dp->ew.work);
4116cbf67842SDouglas Gilbert 	}
4117f46eb0e9SDouglas Gilbert 	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4118f46eb0e9SDouglas Gilbert 		     (scsi_result == device_qfull_result)))
4119cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4120cbf67842SDouglas Gilbert 			    "%s: num_in_q=%d +1, %s%s\n", __func__,
4121cbf67842SDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""),
4122cbf67842SDouglas Gilbert 			    "status: TASK SET FULL");
41231da177e4SLinus Torvalds 	return 0;
4124cd62b7daSDouglas Gilbert 
4125cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
4126cd62b7daSDouglas Gilbert 	cmnd->result = scsi_result;
4127cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
4128cd62b7daSDouglas Gilbert 	return 0;
41291da177e4SLinus Torvalds }
4130cbf67842SDouglas Gilbert 
413123183910SDouglas Gilbert /* Note: The following macros create attribute files in the
413223183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
413323183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
413423183910SDouglas Gilbert    as it can when the corresponding attribute in the
413523183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
413623183910SDouglas Gilbert  */
4137773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4138773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
4139773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
4140c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
4141773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4142773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
4143773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
4144773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4145773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4146773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4147773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4148773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
4149773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4150773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4151773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4152773642d9SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4153773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4154773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4155773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4156773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4157773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4158773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4159773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4160773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4161773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4162773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4163773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
4164773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4165773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4166773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4167773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
4168c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
4169773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
4170c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO);
4171773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4172773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4173773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4174773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4175773642d9SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
417609ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
4177773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
417823183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
4179773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
41805b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
41811da177e4SLinus Torvalds 
41821da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
41831da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
41841da177e4SLinus Torvalds MODULE_LICENSE("GPL");
4185b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION);
41861da177e4SLinus Torvalds 
41871da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
41885b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
41890759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
4190cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
4191c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
41925b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
41935b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
4194c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
4195beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
419623183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
41975b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
4198185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
41995b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
42005b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
42015b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
4202760f3b03SDouglas Gilbert MODULE_PARM_DESC(lbprz,
4203760f3b03SDouglas Gilbert 	"on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
42045b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
4205c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
4206cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4207cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
4208c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
420978d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
42101da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
4211c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
421232c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
42136f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
42145b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
42151da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
4216d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
4217760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
4218ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
4219c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
4220c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
4221c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
42225b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
42235b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
42246014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
42256014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
422609ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl,
422709ba24c1SDouglas Gilbert 		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
4228c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
42295b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
42305b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
42311da177e4SLinus Torvalds 
4232760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256
4233760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN];
42341da177e4SLinus Torvalds 
42351da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp)
42361da177e4SLinus Torvalds {
4237c4837394SDouglas Gilbert 	int k;
4238c4837394SDouglas Gilbert 
4239760f3b03SDouglas Gilbert 	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4240760f3b03SDouglas Gilbert 		      my_name, SDEBUG_VERSION, sdebug_version_date);
4241760f3b03SDouglas Gilbert 	if (k >= (SDEBUG_INFO_LEN - 1))
4242c4837394SDouglas Gilbert 		return sdebug_info;
4243760f3b03SDouglas Gilbert 	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4244760f3b03SDouglas Gilbert 		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4245760f3b03SDouglas Gilbert 		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
4246760f3b03SDouglas Gilbert 		  "statistics", (int)sdebug_statistics);
42471da177e4SLinus Torvalds 	return sdebug_info;
42481da177e4SLinus Torvalds }
42491da177e4SLinus Torvalds 
4250cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
4251fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4252fd32119bSDouglas Gilbert 				 int length)
42531da177e4SLinus Torvalds {
42541da177e4SLinus Torvalds 	char arr[16];
4255c8ed555aSAl Viro 	int opts;
42561da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
42571da177e4SLinus Torvalds 
42581da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
42591da177e4SLinus Torvalds 		return -EACCES;
42601da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
42611da177e4SLinus Torvalds 	arr[minLen] = '\0';
4262c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
42631da177e4SLinus Torvalds 		return -EINVAL;
4264773642d9SDouglas Gilbert 	sdebug_opts = opts;
4265773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4266773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4267773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
4268c4837394SDouglas Gilbert 		tweak_cmnd_count();
42691da177e4SLinus Torvalds 	return length;
42701da177e4SLinus Torvalds }
4271c8ed555aSAl Viro 
4272cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4273cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
4274cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
4275c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4276c8ed555aSAl Viro {
4277c4837394SDouglas Gilbert 	int f, j, l;
4278c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
4279cbf67842SDouglas Gilbert 
4280c4837394SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4281c4837394SDouglas Gilbert 		   SDEBUG_VERSION, sdebug_version_date);
4282c4837394SDouglas Gilbert 	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4283c4837394SDouglas Gilbert 		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4284c4837394SDouglas Gilbert 		   sdebug_opts, sdebug_every_nth);
4285c4837394SDouglas Gilbert 	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4286c4837394SDouglas Gilbert 		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4287c4837394SDouglas Gilbert 		   sdebug_sector_size, "bytes");
4288c4837394SDouglas Gilbert 	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4289c4837394SDouglas Gilbert 		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4290c4837394SDouglas Gilbert 		   num_aborts);
4291c4837394SDouglas Gilbert 	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4292c4837394SDouglas Gilbert 		   num_dev_resets, num_target_resets, num_bus_resets,
4293c4837394SDouglas Gilbert 		   num_host_resets);
4294c4837394SDouglas Gilbert 	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4295c4837394SDouglas Gilbert 		   dix_reads, dix_writes, dif_errors);
4296c4837394SDouglas Gilbert 	seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n",
4297c4837394SDouglas Gilbert 		   TICK_NSEC / 1000, "statistics", sdebug_statistics,
4298c4837394SDouglas Gilbert 		   sdebug_mq_active);
4299c4837394SDouglas Gilbert 	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4300c4837394SDouglas Gilbert 		   atomic_read(&sdebug_cmnd_count),
4301c4837394SDouglas Gilbert 		   atomic_read(&sdebug_completions),
4302c4837394SDouglas Gilbert 		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
4303c4837394SDouglas Gilbert 		   atomic_read(&sdebug_a_tsf));
4304cbf67842SDouglas Gilbert 
4305c4837394SDouglas Gilbert 	seq_printf(m, "submit_queues=%d\n", submit_queues);
4306c4837394SDouglas Gilbert 	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4307c4837394SDouglas Gilbert 		seq_printf(m, "  queue %d:\n", j);
4308c4837394SDouglas Gilbert 		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4309773642d9SDouglas Gilbert 		if (f != sdebug_max_queue) {
4310c4837394SDouglas Gilbert 			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4311c4837394SDouglas Gilbert 			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
4312c4837394SDouglas Gilbert 				   "first,last bits", f, l);
4313c4837394SDouglas Gilbert 		}
4314cbf67842SDouglas Gilbert 	}
4315c8ed555aSAl Viro 	return 0;
43161da177e4SLinus Torvalds }
43171da177e4SLinus Torvalds 
431882069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
43191da177e4SLinus Torvalds {
4320c2206098SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
43211da177e4SLinus Torvalds }
4322c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4323c4837394SDouglas Gilbert  * of delay is jiffies.
4324c4837394SDouglas Gilbert  */
432582069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
432682069379SAkinobu Mita 			   size_t count)
43271da177e4SLinus Torvalds {
4328c2206098SDouglas Gilbert 	int jdelay, res;
43291da177e4SLinus Torvalds 
4330b01f6f83SDouglas Gilbert 	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
4331cbf67842SDouglas Gilbert 		res = count;
4332c2206098SDouglas Gilbert 		if (sdebug_jdelay != jdelay) {
4333c4837394SDouglas Gilbert 			int j, k;
4334c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4335cbf67842SDouglas Gilbert 
4336c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4337c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4338c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4339c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4340c4837394SDouglas Gilbert 						   sdebug_max_queue);
4341c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4342c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4343c4837394SDouglas Gilbert 					break;
4344c4837394SDouglas Gilbert 				}
4345c4837394SDouglas Gilbert 			}
4346c4837394SDouglas Gilbert 			if (res > 0) {
4347a10bc12aSDouglas Gilbert 				/* make sure sdebug_defer instances get
4348a10bc12aSDouglas Gilbert 				 * re-allocated for new delay variant */
4349a10bc12aSDouglas Gilbert 				free_all_queued();
4350c2206098SDouglas Gilbert 				sdebug_jdelay = jdelay;
4351773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
43521da177e4SLinus Torvalds 			}
4353c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4354cbf67842SDouglas Gilbert 		}
4355cbf67842SDouglas Gilbert 		return res;
43561da177e4SLinus Torvalds 	}
43571da177e4SLinus Torvalds 	return -EINVAL;
43581da177e4SLinus Torvalds }
435982069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
43601da177e4SLinus Torvalds 
4361cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4362cbf67842SDouglas Gilbert {
4363773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
4364cbf67842SDouglas Gilbert }
4365cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
4366c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
4367cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
4368cbf67842SDouglas Gilbert 			    size_t count)
4369cbf67842SDouglas Gilbert {
4370c4837394SDouglas Gilbert 	int ndelay, res;
4371cbf67842SDouglas Gilbert 
4372cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4373c4837394SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
4374cbf67842SDouglas Gilbert 		res = count;
4375773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
4376c4837394SDouglas Gilbert 			int j, k;
4377c4837394SDouglas Gilbert 			struct sdebug_queue *sqp;
4378c4837394SDouglas Gilbert 
4379c4837394SDouglas Gilbert 			block_unblock_all_queues(true);
4380c4837394SDouglas Gilbert 			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4381c4837394SDouglas Gilbert 			     ++j, ++sqp) {
4382c4837394SDouglas Gilbert 				k = find_first_bit(sqp->in_use_bm,
4383c4837394SDouglas Gilbert 						   sdebug_max_queue);
4384c4837394SDouglas Gilbert 				if (k != sdebug_max_queue) {
4385c4837394SDouglas Gilbert 					res = -EBUSY;   /* queued commands */
4386c4837394SDouglas Gilbert 					break;
4387c4837394SDouglas Gilbert 				}
4388c4837394SDouglas Gilbert 			}
4389c4837394SDouglas Gilbert 			if (res > 0) {
4390a10bc12aSDouglas Gilbert 				/* make sure sdebug_defer instances get
4391a10bc12aSDouglas Gilbert 				 * re-allocated for new delay variant */
4392a10bc12aSDouglas Gilbert 				free_all_queued();
4393773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
4394c2206098SDouglas Gilbert 				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
4395c2206098SDouglas Gilbert 							: DEF_JDELAY;
4396cbf67842SDouglas Gilbert 			}
4397c4837394SDouglas Gilbert 			block_unblock_all_queues(false);
4398cbf67842SDouglas Gilbert 		}
4399cbf67842SDouglas Gilbert 		return res;
4400cbf67842SDouglas Gilbert 	}
4401cbf67842SDouglas Gilbert 	return -EINVAL;
4402cbf67842SDouglas Gilbert }
4403cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
4404cbf67842SDouglas Gilbert 
440582069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
44061da177e4SLinus Torvalds {
4407773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
44081da177e4SLinus Torvalds }
44091da177e4SLinus Torvalds 
441082069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
441182069379SAkinobu Mita 			  size_t count)
44121da177e4SLinus Torvalds {
44131da177e4SLinus Torvalds         int opts;
44141da177e4SLinus Torvalds 	char work[20];
44151da177e4SLinus Torvalds 
44161da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
441748a96876SRasmus Villemoes 		if (0 == strncasecmp(work,"0x", 2)) {
44181da177e4SLinus Torvalds 			if (1 == sscanf(&work[2], "%x", &opts))
44191da177e4SLinus Torvalds 				goto opts_done;
44201da177e4SLinus Torvalds 		} else {
44211da177e4SLinus Torvalds 			if (1 == sscanf(work, "%d", &opts))
44221da177e4SLinus Torvalds 				goto opts_done;
44231da177e4SLinus Torvalds 		}
44241da177e4SLinus Torvalds 	}
44251da177e4SLinus Torvalds 	return -EINVAL;
44261da177e4SLinus Torvalds opts_done:
4427773642d9SDouglas Gilbert 	sdebug_opts = opts;
4428773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4429773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4430c4837394SDouglas Gilbert 	tweak_cmnd_count();
44311da177e4SLinus Torvalds 	return count;
44321da177e4SLinus Torvalds }
443382069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
44341da177e4SLinus Torvalds 
443582069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
44361da177e4SLinus Torvalds {
4437773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
44381da177e4SLinus Torvalds }
443982069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
444082069379SAkinobu Mita 			   size_t count)
44411da177e4SLinus Torvalds {
44421da177e4SLinus Torvalds         int n;
44431da177e4SLinus Torvalds 
44441da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4445773642d9SDouglas Gilbert 		sdebug_ptype = n;
44461da177e4SLinus Torvalds 		return count;
44471da177e4SLinus Torvalds 	}
44481da177e4SLinus Torvalds 	return -EINVAL;
44491da177e4SLinus Torvalds }
445082069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
44511da177e4SLinus Torvalds 
445282069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
44531da177e4SLinus Torvalds {
4454773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
44551da177e4SLinus Torvalds }
445682069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
445782069379SAkinobu Mita 			    size_t count)
44581da177e4SLinus Torvalds {
44591da177e4SLinus Torvalds         int n;
44601da177e4SLinus Torvalds 
44611da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4462773642d9SDouglas Gilbert 		sdebug_dsense = n;
44631da177e4SLinus Torvalds 		return count;
44641da177e4SLinus Torvalds 	}
44651da177e4SLinus Torvalds 	return -EINVAL;
44661da177e4SLinus Torvalds }
446782069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
44681da177e4SLinus Torvalds 
446982069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
447023183910SDouglas Gilbert {
4471773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
447223183910SDouglas Gilbert }
447382069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
447482069379SAkinobu Mita 			     size_t count)
447523183910SDouglas Gilbert {
447623183910SDouglas Gilbert         int n;
447723183910SDouglas Gilbert 
447823183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4479cbf67842SDouglas Gilbert 		n = (n > 0);
4480773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
4481773642d9SDouglas Gilbert 		if (sdebug_fake_rw != n) {
4482cbf67842SDouglas Gilbert 			if ((0 == n) && (NULL == fake_storep)) {
4483cbf67842SDouglas Gilbert 				unsigned long sz =
4484773642d9SDouglas Gilbert 					(unsigned long)sdebug_dev_size_mb *
4485cbf67842SDouglas Gilbert 					1048576;
4486cbf67842SDouglas Gilbert 
4487cbf67842SDouglas Gilbert 				fake_storep = vmalloc(sz);
4488cbf67842SDouglas Gilbert 				if (NULL == fake_storep) {
4489c1287970STomas Winkler 					pr_err("out of memory, 9\n");
4490cbf67842SDouglas Gilbert 					return -ENOMEM;
4491cbf67842SDouglas Gilbert 				}
4492cbf67842SDouglas Gilbert 				memset(fake_storep, 0, sz);
4493cbf67842SDouglas Gilbert 			}
4494773642d9SDouglas Gilbert 			sdebug_fake_rw = n;
4495cbf67842SDouglas Gilbert 		}
449623183910SDouglas Gilbert 		return count;
449723183910SDouglas Gilbert 	}
449823183910SDouglas Gilbert 	return -EINVAL;
449923183910SDouglas Gilbert }
450082069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
450123183910SDouglas Gilbert 
450282069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
4503c65b1445SDouglas Gilbert {
4504773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
4505c65b1445SDouglas Gilbert }
450682069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
450782069379SAkinobu Mita 			      size_t count)
4508c65b1445SDouglas Gilbert {
4509c65b1445SDouglas Gilbert         int n;
4510c65b1445SDouglas Gilbert 
4511c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4512773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
4513c65b1445SDouglas Gilbert 		return count;
4514c65b1445SDouglas Gilbert 	}
4515c65b1445SDouglas Gilbert 	return -EINVAL;
4516c65b1445SDouglas Gilbert }
451782069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
4518c65b1445SDouglas Gilbert 
451982069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
45201da177e4SLinus Torvalds {
4521773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
45221da177e4SLinus Torvalds }
452382069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
452482069379SAkinobu Mita 			      size_t count)
45251da177e4SLinus Torvalds {
45261da177e4SLinus Torvalds         int n;
45271da177e4SLinus Torvalds 
45281da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4529773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
45301da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
45311da177e4SLinus Torvalds 		return count;
45321da177e4SLinus Torvalds 	}
45331da177e4SLinus Torvalds 	return -EINVAL;
45341da177e4SLinus Torvalds }
453582069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
45361da177e4SLinus Torvalds 
453782069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
45381da177e4SLinus Torvalds {
4539773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
45401da177e4SLinus Torvalds }
454182069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
45421da177e4SLinus Torvalds 
454382069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
45441da177e4SLinus Torvalds {
4545773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
45461da177e4SLinus Torvalds }
454782069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
45481da177e4SLinus Torvalds 
454982069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
45501da177e4SLinus Torvalds {
4551773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
45521da177e4SLinus Torvalds }
455382069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
455482069379SAkinobu Mita 			       size_t count)
45551da177e4SLinus Torvalds {
45561da177e4SLinus Torvalds         int nth;
45571da177e4SLinus Torvalds 
45581da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
4559773642d9SDouglas Gilbert 		sdebug_every_nth = nth;
4560c4837394SDouglas Gilbert 		if (nth && !sdebug_statistics) {
4561c4837394SDouglas Gilbert 			pr_info("every_nth needs statistics=1, set it\n");
4562c4837394SDouglas Gilbert 			sdebug_statistics = true;
4563c4837394SDouglas Gilbert 		}
4564c4837394SDouglas Gilbert 		tweak_cmnd_count();
45651da177e4SLinus Torvalds 		return count;
45661da177e4SLinus Torvalds 	}
45671da177e4SLinus Torvalds 	return -EINVAL;
45681da177e4SLinus Torvalds }
456982069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
45701da177e4SLinus Torvalds 
457182069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
45721da177e4SLinus Torvalds {
4573773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
45741da177e4SLinus Torvalds }
457582069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
457682069379SAkinobu Mita 			      size_t count)
45771da177e4SLinus Torvalds {
45781da177e4SLinus Torvalds         int n;
457919c8ead7SEwan D. Milne 	bool changed;
45801da177e4SLinus Torvalds 
45811da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
45828d039e22SDouglas Gilbert 		if (n > 256) {
45838d039e22SDouglas Gilbert 			pr_warn("max_luns can be no more than 256\n");
45848d039e22SDouglas Gilbert 			return -EINVAL;
45858d039e22SDouglas Gilbert 		}
4586773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
4587773642d9SDouglas Gilbert 		sdebug_max_luns = n;
45881da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
4589773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
459019c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
459119c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
459219c8ead7SEwan D. Milne 
459319c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
459419c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
459519c8ead7SEwan D. Milne 					    host_list) {
459619c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
459719c8ead7SEwan D. Milne 						    dev_list) {
459819c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
459919c8ead7SEwan D. Milne 						dp->uas_bm);
460019c8ead7SEwan D. Milne 				}
460119c8ead7SEwan D. Milne 			}
460219c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
460319c8ead7SEwan D. Milne 		}
46041da177e4SLinus Torvalds 		return count;
46051da177e4SLinus Torvalds 	}
46061da177e4SLinus Torvalds 	return -EINVAL;
46071da177e4SLinus Torvalds }
460882069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
46091da177e4SLinus Torvalds 
461082069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
461178d4e5a0SDouglas Gilbert {
4612773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
461378d4e5a0SDouglas Gilbert }
4614cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
4615cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
461682069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
461782069379SAkinobu Mita 			       size_t count)
461878d4e5a0SDouglas Gilbert {
4619c4837394SDouglas Gilbert 	int j, n, k, a;
4620c4837394SDouglas Gilbert 	struct sdebug_queue *sqp;
462178d4e5a0SDouglas Gilbert 
462278d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
4623c4837394SDouglas Gilbert 	    (n <= SDEBUG_CANQUEUE)) {
4624c4837394SDouglas Gilbert 		block_unblock_all_queues(true);
4625c4837394SDouglas Gilbert 		k = 0;
4626c4837394SDouglas Gilbert 		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4627c4837394SDouglas Gilbert 		     ++j, ++sqp) {
4628c4837394SDouglas Gilbert 			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4629c4837394SDouglas Gilbert 			if (a > k)
4630c4837394SDouglas Gilbert 				k = a;
4631c4837394SDouglas Gilbert 		}
4632773642d9SDouglas Gilbert 		sdebug_max_queue = n;
4633c4837394SDouglas Gilbert 		if (k == SDEBUG_CANQUEUE)
4634cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4635cbf67842SDouglas Gilbert 		else if (k >= n)
4636cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4637cbf67842SDouglas Gilbert 		else
4638cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4639c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
464078d4e5a0SDouglas Gilbert 		return count;
464178d4e5a0SDouglas Gilbert 	}
464278d4e5a0SDouglas Gilbert 	return -EINVAL;
464378d4e5a0SDouglas Gilbert }
464482069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
464578d4e5a0SDouglas Gilbert 
464682069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
464778d4e5a0SDouglas Gilbert {
4648773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
464978d4e5a0SDouglas Gilbert }
465082069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
465178d4e5a0SDouglas Gilbert 
465282069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
46531da177e4SLinus Torvalds {
4654773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
46551da177e4SLinus Torvalds }
465682069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
46571da177e4SLinus Torvalds 
465882069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
4659c65b1445SDouglas Gilbert {
4660773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
4661c65b1445SDouglas Gilbert }
466282069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
466382069379SAkinobu Mita 				size_t count)
4664c65b1445SDouglas Gilbert {
4665c65b1445SDouglas Gilbert         int n;
46660d01c5dfSDouglas Gilbert 	bool changed;
4667c65b1445SDouglas Gilbert 
4668c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4669773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
4670773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
467128898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
46720d01c5dfSDouglas Gilbert 		if (changed) {
46730d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
46740d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
467528898873SFUJITA Tomonori 
46764bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
46770d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
46780d01c5dfSDouglas Gilbert 					    host_list) {
46790d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
46800d01c5dfSDouglas Gilbert 						    dev_list) {
46810d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
46820d01c5dfSDouglas Gilbert 						dp->uas_bm);
46830d01c5dfSDouglas Gilbert 				}
46840d01c5dfSDouglas Gilbert 			}
46854bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
46860d01c5dfSDouglas Gilbert 		}
4687c65b1445SDouglas Gilbert 		return count;
4688c65b1445SDouglas Gilbert 	}
4689c65b1445SDouglas Gilbert 	return -EINVAL;
4690c65b1445SDouglas Gilbert }
469182069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
4692c65b1445SDouglas Gilbert 
469382069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
46941da177e4SLinus Torvalds {
4695773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
46961da177e4SLinus Torvalds }
46971da177e4SLinus Torvalds 
4698fd32119bSDouglas Gilbert static int sdebug_add_adapter(void);
4699fd32119bSDouglas Gilbert static void sdebug_remove_adapter(void);
4700fd32119bSDouglas Gilbert 
470182069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
470282069379SAkinobu Mita 			      size_t count)
47031da177e4SLinus Torvalds {
47041da177e4SLinus Torvalds 	int delta_hosts;
47051da177e4SLinus Torvalds 
4706f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
47071da177e4SLinus Torvalds 		return -EINVAL;
47081da177e4SLinus Torvalds 	if (delta_hosts > 0) {
47091da177e4SLinus Torvalds 		do {
47101da177e4SLinus Torvalds 			sdebug_add_adapter();
47111da177e4SLinus Torvalds 		} while (--delta_hosts);
47121da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
47131da177e4SLinus Torvalds 		do {
47141da177e4SLinus Torvalds 			sdebug_remove_adapter();
47151da177e4SLinus Torvalds 		} while (++delta_hosts);
47161da177e4SLinus Torvalds 	}
47171da177e4SLinus Torvalds 	return count;
47181da177e4SLinus Torvalds }
471982069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
47201da177e4SLinus Torvalds 
472182069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
472223183910SDouglas Gilbert {
4723773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
472423183910SDouglas Gilbert }
472582069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
472682069379SAkinobu Mita 				    size_t count)
472723183910SDouglas Gilbert {
472823183910SDouglas Gilbert 	int n;
472923183910SDouglas Gilbert 
473023183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4731773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
473223183910SDouglas Gilbert 		return count;
473323183910SDouglas Gilbert 	}
473423183910SDouglas Gilbert 	return -EINVAL;
473523183910SDouglas Gilbert }
473682069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
473723183910SDouglas Gilbert 
4738c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf)
4739c4837394SDouglas Gilbert {
4740c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
4741c4837394SDouglas Gilbert }
4742c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
4743c4837394SDouglas Gilbert 				size_t count)
4744c4837394SDouglas Gilbert {
4745c4837394SDouglas Gilbert 	int n;
4746c4837394SDouglas Gilbert 
4747c4837394SDouglas Gilbert 	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
4748c4837394SDouglas Gilbert 		if (n > 0)
4749c4837394SDouglas Gilbert 			sdebug_statistics = true;
4750c4837394SDouglas Gilbert 		else {
4751c4837394SDouglas Gilbert 			clear_queue_stats();
4752c4837394SDouglas Gilbert 			sdebug_statistics = false;
4753c4837394SDouglas Gilbert 		}
4754c4837394SDouglas Gilbert 		return count;
4755c4837394SDouglas Gilbert 	}
4756c4837394SDouglas Gilbert 	return -EINVAL;
4757c4837394SDouglas Gilbert }
4758c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics);
4759c4837394SDouglas Gilbert 
476082069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
4761597136abSMartin K. Petersen {
4762773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
4763597136abSMartin K. Petersen }
476482069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
4765597136abSMartin K. Petersen 
4766c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
4767c4837394SDouglas Gilbert {
4768c4837394SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
4769c4837394SDouglas Gilbert }
4770c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues);
4771c4837394SDouglas Gilbert 
477282069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
4773c6a44287SMartin K. Petersen {
4774773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
4775c6a44287SMartin K. Petersen }
477682069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
4777c6a44287SMartin K. Petersen 
477882069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
4779c6a44287SMartin K. Petersen {
4780773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
4781c6a44287SMartin K. Petersen }
478282069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
4783c6a44287SMartin K. Petersen 
478482069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
4785c6a44287SMartin K. Petersen {
4786773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
4787c6a44287SMartin K. Petersen }
478882069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
4789c6a44287SMartin K. Petersen 
479082069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
4791c6a44287SMartin K. Petersen {
4792773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
4793c6a44287SMartin K. Petersen }
479482069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
4795c6a44287SMartin K. Petersen 
479682069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
479744d92694SMartin K. Petersen {
479844d92694SMartin K. Petersen 	ssize_t count;
479944d92694SMartin K. Petersen 
48005b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
480144d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
480244d92694SMartin K. Petersen 				 sdebug_store_sectors);
480344d92694SMartin K. Petersen 
4804c7badc90STejun Heo 	count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
4805c7badc90STejun Heo 			  (int)map_size, map_storep);
480644d92694SMartin K. Petersen 	buf[count++] = '\n';
4807c7badc90STejun Heo 	buf[count] = '\0';
480844d92694SMartin K. Petersen 
480944d92694SMartin K. Petersen 	return count;
481044d92694SMartin K. Petersen }
481182069379SAkinobu Mita static DRIVER_ATTR_RO(map);
481244d92694SMartin K. Petersen 
481382069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
4814d986788bSMartin Pitt {
4815773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
4816d986788bSMartin Pitt }
481782069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
481882069379SAkinobu Mita 			       size_t count)
4819d986788bSMartin Pitt {
4820d986788bSMartin Pitt 	int n;
4821d986788bSMartin Pitt 
4822d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4823773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
4824d986788bSMartin Pitt 		return count;
4825d986788bSMartin Pitt 	}
4826d986788bSMartin Pitt 	return -EINVAL;
4827d986788bSMartin Pitt }
482882069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
4829d986788bSMartin Pitt 
4830cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4831cbf67842SDouglas Gilbert {
4832773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
4833cbf67842SDouglas Gilbert }
4834185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
4835cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4836cbf67842SDouglas Gilbert 			       size_t count)
4837cbf67842SDouglas Gilbert {
4838185dd232SDouglas Gilbert 	int n;
4839cbf67842SDouglas Gilbert 
4840cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4841185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
4842185dd232SDouglas Gilbert 		return count;
4843cbf67842SDouglas Gilbert 	}
4844cbf67842SDouglas Gilbert 	return -EINVAL;
4845cbf67842SDouglas Gilbert }
4846cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
4847cbf67842SDouglas Gilbert 
4848c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
4849c2248fc9SDouglas Gilbert {
4850773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
4851c2248fc9SDouglas Gilbert }
4852c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4853c2248fc9SDouglas Gilbert 			    size_t count)
4854c2248fc9SDouglas Gilbert {
4855c2248fc9SDouglas Gilbert 	int n;
4856c2248fc9SDouglas Gilbert 
4857c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4858773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
4859c2248fc9SDouglas Gilbert 		return count;
4860c2248fc9SDouglas Gilbert 	}
4861c2248fc9SDouglas Gilbert 	return -EINVAL;
4862c2248fc9SDouglas Gilbert }
4863c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
4864c2248fc9SDouglas Gilbert 
486509ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
486609ba24c1SDouglas Gilbert {
486709ba24c1SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
486809ba24c1SDouglas Gilbert }
486909ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl);
487009ba24c1SDouglas Gilbert 
4871cbf67842SDouglas Gilbert 
487282069379SAkinobu Mita /* Note: The following array creates attribute files in the
487323183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
487423183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
487523183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
487623183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
487723183910SDouglas Gilbert  */
48786ecaff7fSRandy Dunlap 
487982069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
488082069379SAkinobu Mita 	&driver_attr_delay.attr,
488182069379SAkinobu Mita 	&driver_attr_opts.attr,
488282069379SAkinobu Mita 	&driver_attr_ptype.attr,
488382069379SAkinobu Mita 	&driver_attr_dsense.attr,
488482069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
488582069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
488682069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
488782069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
488882069379SAkinobu Mita 	&driver_attr_num_parts.attr,
488982069379SAkinobu Mita 	&driver_attr_every_nth.attr,
489082069379SAkinobu Mita 	&driver_attr_max_luns.attr,
489182069379SAkinobu Mita 	&driver_attr_max_queue.attr,
489282069379SAkinobu Mita 	&driver_attr_no_uld.attr,
489382069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
489482069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
489582069379SAkinobu Mita 	&driver_attr_add_host.attr,
489682069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
489782069379SAkinobu Mita 	&driver_attr_sector_size.attr,
4898c4837394SDouglas Gilbert 	&driver_attr_statistics.attr,
4899c4837394SDouglas Gilbert 	&driver_attr_submit_queues.attr,
490082069379SAkinobu Mita 	&driver_attr_dix.attr,
490182069379SAkinobu Mita 	&driver_attr_dif.attr,
490282069379SAkinobu Mita 	&driver_attr_guard.attr,
490382069379SAkinobu Mita 	&driver_attr_ato.attr,
490482069379SAkinobu Mita 	&driver_attr_map.attr,
490582069379SAkinobu Mita 	&driver_attr_removable.attr,
4906cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
4907cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
4908c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
490909ba24c1SDouglas Gilbert 	&driver_attr_uuid_ctl.attr,
491082069379SAkinobu Mita 	NULL,
491182069379SAkinobu Mita };
491282069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
49131da177e4SLinus Torvalds 
491411ddcecaSAkinobu Mita static struct device *pseudo_primary;
49158dea0d02SFUJITA Tomonori 
49161da177e4SLinus Torvalds static int __init scsi_debug_init(void)
49171da177e4SLinus Torvalds {
49185f2578e5SFUJITA Tomonori 	unsigned long sz;
49191da177e4SLinus Torvalds 	int host_to_add;
49201da177e4SLinus Torvalds 	int k;
49216ecaff7fSRandy Dunlap 	int ret;
49221da177e4SLinus Torvalds 
4923cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
4924cbf67842SDouglas Gilbert 
4925773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
4926c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
4927773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
4928773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
4929c2206098SDouglas Gilbert 		sdebug_jdelay = JDELAY_OVERRIDDEN;
4930cbf67842SDouglas Gilbert 
4931773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
4932597136abSMartin K. Petersen 	case  512:
4933597136abSMartin K. Petersen 	case 1024:
4934597136abSMartin K. Petersen 	case 2048:
4935597136abSMartin K. Petersen 	case 4096:
4936597136abSMartin K. Petersen 		break;
4937597136abSMartin K. Petersen 	default:
4938773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
4939597136abSMartin K. Petersen 		return -EINVAL;
4940597136abSMartin K. Petersen 	}
4941597136abSMartin K. Petersen 
4942773642d9SDouglas Gilbert 	switch (sdebug_dif) {
49438475c811SChristoph Hellwig 	case T10_PI_TYPE0_PROTECTION:
4944f46eb0e9SDouglas Gilbert 		break;
49458475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
49468475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
49478475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
4948f46eb0e9SDouglas Gilbert 		have_dif_prot = true;
4949c6a44287SMartin K. Petersen 		break;
4950c6a44287SMartin K. Petersen 
4951c6a44287SMartin K. Petersen 	default:
4952c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
4953c6a44287SMartin K. Petersen 		return -EINVAL;
4954c6a44287SMartin K. Petersen 	}
4955c6a44287SMartin K. Petersen 
4956773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
4957c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
4958c6a44287SMartin K. Petersen 		return -EINVAL;
4959c6a44287SMartin K. Petersen 	}
4960c6a44287SMartin K. Petersen 
4961773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
4962c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
4963c6a44287SMartin K. Petersen 		return -EINVAL;
4964c6a44287SMartin K. Petersen 	}
4965c6a44287SMartin K. Petersen 
4966773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
4967773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
4968ea61fca5SMartin K. Petersen 		return -EINVAL;
4969ea61fca5SMartin K. Petersen 	}
49708d039e22SDouglas Gilbert 	if (sdebug_max_luns > 256) {
49718d039e22SDouglas Gilbert 		pr_warn("max_luns can be no more than 256, use default\n");
49728d039e22SDouglas Gilbert 		sdebug_max_luns = DEF_MAX_LUNS;
49738d039e22SDouglas Gilbert 	}
4974ea61fca5SMartin K. Petersen 
4975773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
4976773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
4977ea61fca5SMartin K. Petersen 		return -EINVAL;
4978ea61fca5SMartin K. Petersen 	}
4979ea61fca5SMartin K. Petersen 
4980c4837394SDouglas Gilbert 	if (submit_queues < 1) {
4981c4837394SDouglas Gilbert 		pr_err("submit_queues must be 1 or more\n");
4982c4837394SDouglas Gilbert 		return -EINVAL;
4983c4837394SDouglas Gilbert 	}
4984c4837394SDouglas Gilbert 	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
4985c4837394SDouglas Gilbert 			       GFP_KERNEL);
4986c4837394SDouglas Gilbert 	if (sdebug_q_arr == NULL)
4987c4837394SDouglas Gilbert 		return -ENOMEM;
4988c4837394SDouglas Gilbert 	for (k = 0; k < submit_queues; ++k)
4989c4837394SDouglas Gilbert 		spin_lock_init(&sdebug_q_arr[k].qc_lock);
4990c4837394SDouglas Gilbert 
4991773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
4992773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
4993773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
4994773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
499528898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
49961da177e4SLinus Torvalds 
49971da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
49981da177e4SLinus Torvalds 	sdebug_heads = 8;
49991da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
5000773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
50011da177e4SLinus Torvalds 		sdebug_heads = 64;
5002773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
5003fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
50041da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
50051da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
50061da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
50071da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
50081da177e4SLinus Torvalds 		sdebug_heads = 255;
50091da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
50101da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
50111da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
50121da177e4SLinus Torvalds 	}
50131da177e4SLinus Torvalds 
5014b01f6f83SDouglas Gilbert 	if (sdebug_fake_rw == 0) {
50151da177e4SLinus Torvalds 		fake_storep = vmalloc(sz);
50161da177e4SLinus Torvalds 		if (NULL == fake_storep) {
5017c1287970STomas Winkler 			pr_err("out of memory, 1\n");
5018c4837394SDouglas Gilbert 			ret = -ENOMEM;
5019c4837394SDouglas Gilbert 			goto free_q_arr;
50201da177e4SLinus Torvalds 		}
50211da177e4SLinus Torvalds 		memset(fake_storep, 0, sz);
5022773642d9SDouglas Gilbert 		if (sdebug_num_parts > 0)
5023f58b0efbSFUJITA Tomonori 			sdebug_build_parts(fake_storep, sz);
5024cbf67842SDouglas Gilbert 	}
50251da177e4SLinus Torvalds 
5026773642d9SDouglas Gilbert 	if (sdebug_dix) {
5027c6a44287SMartin K. Petersen 		int dif_size;
5028c6a44287SMartin K. Petersen 
50296ebf105cSChristoph Hellwig 		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
5030c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
5031c6a44287SMartin K. Petersen 
5032c1287970STomas Winkler 		pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
5033c6a44287SMartin K. Petersen 
5034c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
5035c1287970STomas Winkler 			pr_err("out of mem. (DIX)\n");
5036c6a44287SMartin K. Petersen 			ret = -ENOMEM;
5037c6a44287SMartin K. Petersen 			goto free_vm;
5038c6a44287SMartin K. Petersen 		}
5039c6a44287SMartin K. Petersen 
5040c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
5041c6a44287SMartin K. Petersen 	}
5042c6a44287SMartin K. Petersen 
50435b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
50445b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
5045773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
5046773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
50476014759cSMartin K. Petersen 
5048773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
5049773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
50506014759cSMartin K. Petersen 
5051773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
5052773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
50536014759cSMartin K. Petersen 
5054773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
5055773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
5056773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
5057c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
5058c4837394SDouglas Gilbert 			ret = -EINVAL;
5059c4837394SDouglas Gilbert 			goto free_vm;
506044d92694SMartin K. Petersen 		}
506144d92694SMartin K. Petersen 
5062b90ebc3dSAkinobu Mita 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
5063b90ebc3dSAkinobu Mita 		map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
506444d92694SMartin K. Petersen 
5065c1287970STomas Winkler 		pr_info("%lu provisioning blocks\n", map_size);
506644d92694SMartin K. Petersen 
506744d92694SMartin K. Petersen 		if (map_storep == NULL) {
5068c1287970STomas Winkler 			pr_err("out of mem. (MAP)\n");
506944d92694SMartin K. Petersen 			ret = -ENOMEM;
507044d92694SMartin K. Petersen 			goto free_vm;
507144d92694SMartin K. Petersen 		}
507244d92694SMartin K. Petersen 
5073b90ebc3dSAkinobu Mita 		bitmap_zero(map_storep, map_size);
507444d92694SMartin K. Petersen 
507544d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
5076773642d9SDouglas Gilbert 		if (sdebug_num_parts)
507744d92694SMartin K. Petersen 			map_region(0, 2);
507844d92694SMartin K. Petersen 	}
507944d92694SMartin K. Petersen 
50809b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
50819b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
5082c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
50839b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
50846ecaff7fSRandy Dunlap 		goto free_vm;
50856ecaff7fSRandy Dunlap 	}
50866ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
50876ecaff7fSRandy Dunlap 	if (ret < 0) {
5088c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
50896ecaff7fSRandy Dunlap 		goto dev_unreg;
50906ecaff7fSRandy Dunlap 	}
50916ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
50926ecaff7fSRandy Dunlap 	if (ret < 0) {
5093c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
50946ecaff7fSRandy Dunlap 		goto bus_unreg;
50956ecaff7fSRandy Dunlap 	}
50961da177e4SLinus Torvalds 
5097773642d9SDouglas Gilbert 	host_to_add = sdebug_add_host;
5098773642d9SDouglas Gilbert 	sdebug_add_host = 0;
50991da177e4SLinus Torvalds 
51001da177e4SLinus Torvalds         for (k = 0; k < host_to_add; k++) {
51011da177e4SLinus Torvalds                 if (sdebug_add_adapter()) {
5102c1287970STomas Winkler 			pr_err("sdebug_add_adapter failed k=%d\n", k);
51031da177e4SLinus Torvalds                         break;
51041da177e4SLinus Torvalds                 }
51051da177e4SLinus Torvalds         }
51061da177e4SLinus Torvalds 
5107773642d9SDouglas Gilbert 	if (sdebug_verbose)
5108773642d9SDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_add_host);
5109c1287970STomas Winkler 
51101da177e4SLinus Torvalds 	return 0;
51116ecaff7fSRandy Dunlap 
51126ecaff7fSRandy Dunlap bus_unreg:
51136ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
51146ecaff7fSRandy Dunlap dev_unreg:
51159b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
51166ecaff7fSRandy Dunlap free_vm:
511744d92694SMartin K. Petersen 	vfree(map_storep);
5118c6a44287SMartin K. Petersen 	vfree(dif_storep);
51196ecaff7fSRandy Dunlap 	vfree(fake_storep);
5120c4837394SDouglas Gilbert free_q_arr:
5121c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
51226ecaff7fSRandy Dunlap 	return ret;
51231da177e4SLinus Torvalds }
51241da177e4SLinus Torvalds 
51251da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
51261da177e4SLinus Torvalds {
5127773642d9SDouglas Gilbert 	int k = sdebug_add_host;
51281da177e4SLinus Torvalds 
51291da177e4SLinus Torvalds 	stop_all_queued();
5130cbf67842SDouglas Gilbert 	free_all_queued();
51311da177e4SLinus Torvalds 	for (; k; k--)
51321da177e4SLinus Torvalds 		sdebug_remove_adapter();
51331da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
51341da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
51359b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
51361da177e4SLinus Torvalds 
51374d2b496fSEwan D. Milne 	vfree(map_storep);
5138c6a44287SMartin K. Petersen 	vfree(dif_storep);
51391da177e4SLinus Torvalds 	vfree(fake_storep);
5140c4837394SDouglas Gilbert 	kfree(sdebug_q_arr);
51411da177e4SLinus Torvalds }
51421da177e4SLinus Torvalds 
51431da177e4SLinus Torvalds device_initcall(scsi_debug_init);
51441da177e4SLinus Torvalds module_exit(scsi_debug_exit);
51451da177e4SLinus Torvalds 
51461da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev)
51471da177e4SLinus Torvalds {
51481da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
51491da177e4SLinus Torvalds 
51501da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
51511da177e4SLinus Torvalds         kfree(sdbg_host);
51521da177e4SLinus Torvalds }
51531da177e4SLinus Torvalds 
51541da177e4SLinus Torvalds static int sdebug_add_adapter(void)
51551da177e4SLinus Torvalds {
51561da177e4SLinus Torvalds 	int k, devs_per_host;
51571da177e4SLinus Torvalds         int error = 0;
51581da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
51598b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
51601da177e4SLinus Torvalds 
516124669f75SJes Sorensen         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
51621da177e4SLinus Torvalds         if (NULL == sdbg_host) {
5163c1287970STomas Winkler 		pr_err("out of memory at line %d\n", __LINE__);
51641da177e4SLinus Torvalds                 return -ENOMEM;
51651da177e4SLinus Torvalds         }
51661da177e4SLinus Torvalds 
51671da177e4SLinus Torvalds         INIT_LIST_HEAD(&sdbg_host->dev_info_list);
51681da177e4SLinus Torvalds 
5169773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
51701da177e4SLinus Torvalds         for (k = 0; k < devs_per_host; k++) {
51715cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
51725cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
5173c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
51741da177e4SLinus Torvalds                         error = -ENOMEM;
51751da177e4SLinus Torvalds 			goto clean;
51761da177e4SLinus Torvalds                 }
51771da177e4SLinus Torvalds         }
51781da177e4SLinus Torvalds 
51791da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
51801da177e4SLinus Torvalds         list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
51811da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
51821da177e4SLinus Torvalds 
51831da177e4SLinus Torvalds         sdbg_host->dev.bus = &pseudo_lld_bus;
51849b906779SNicholas Bellinger         sdbg_host->dev.parent = pseudo_primary;
51851da177e4SLinus Torvalds         sdbg_host->dev.release = &sdebug_release_adapter;
5186773642d9SDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
51871da177e4SLinus Torvalds 
51881da177e4SLinus Torvalds         error = device_register(&sdbg_host->dev);
51891da177e4SLinus Torvalds 
51901da177e4SLinus Torvalds         if (error)
51911da177e4SLinus Torvalds 		goto clean;
51921da177e4SLinus Torvalds 
5193773642d9SDouglas Gilbert 	++sdebug_add_host;
51941da177e4SLinus Torvalds         return error;
51951da177e4SLinus Torvalds 
51961da177e4SLinus Torvalds clean:
51978b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
51988b40228fSFUJITA Tomonori 				 dev_list) {
51991da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
52001da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
52011da177e4SLinus Torvalds 	}
52021da177e4SLinus Torvalds 
52031da177e4SLinus Torvalds 	kfree(sdbg_host);
52041da177e4SLinus Torvalds         return error;
52051da177e4SLinus Torvalds }
52061da177e4SLinus Torvalds 
52071da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
52081da177e4SLinus Torvalds {
52091da177e4SLinus Torvalds         struct sdebug_host_info * sdbg_host = NULL;
52101da177e4SLinus Torvalds 
52111da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
52121da177e4SLinus Torvalds         if (!list_empty(&sdebug_host_list)) {
52131da177e4SLinus Torvalds                 sdbg_host = list_entry(sdebug_host_list.prev,
52141da177e4SLinus Torvalds                                        struct sdebug_host_info, host_list);
52151da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
52161da177e4SLinus Torvalds 	}
52171da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
52181da177e4SLinus Torvalds 
52191da177e4SLinus Torvalds 	if (!sdbg_host)
52201da177e4SLinus Torvalds 		return;
52211da177e4SLinus Torvalds 
52221da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
5223773642d9SDouglas Gilbert 	--sdebug_add_host;
52241da177e4SLinus Torvalds }
52251da177e4SLinus Torvalds 
5226fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
5227cbf67842SDouglas Gilbert {
5228cbf67842SDouglas Gilbert 	int num_in_q = 0;
5229cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5230cbf67842SDouglas Gilbert 
5231c4837394SDouglas Gilbert 	block_unblock_all_queues(true);
5232cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
5233cbf67842SDouglas Gilbert 	if (NULL == devip) {
5234c4837394SDouglas Gilbert 		block_unblock_all_queues(false);
5235cbf67842SDouglas Gilbert 		return	-ENODEV;
5236cbf67842SDouglas Gilbert 	}
5237cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5238c40ecc12SChristoph Hellwig 
5239cbf67842SDouglas Gilbert 	if (qdepth < 1)
5240cbf67842SDouglas Gilbert 		qdepth = 1;
5241c4837394SDouglas Gilbert 	/* allow to exceed max host qc_arr elements for testing */
5242c4837394SDouglas Gilbert 	if (qdepth > SDEBUG_CANQUEUE + 10)
5243c4837394SDouglas Gilbert 		qdepth = SDEBUG_CANQUEUE + 10;
5244db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
5245cbf67842SDouglas Gilbert 
5246773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
5247c4837394SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
5248c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
5249cbf67842SDouglas Gilbert 	}
5250c4837394SDouglas Gilbert 	block_unblock_all_queues(false);
5251cbf67842SDouglas Gilbert 	return sdev->queue_depth;
5252cbf67842SDouglas Gilbert }
5253cbf67842SDouglas Gilbert 
5254c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp)
5255817fd66bSDouglas Gilbert {
5256c4837394SDouglas Gilbert 	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
5257773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
5258773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
5259773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
5260c4837394SDouglas Gilbert 			return true; /* ignore command causing timeout */
5261773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
5262817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
5263c4837394SDouglas Gilbert 			return true; /* time out reads and writes */
5264817fd66bSDouglas Gilbert 	}
5265c4837394SDouglas Gilbert 	return false;
5266817fd66bSDouglas Gilbert }
5267817fd66bSDouglas Gilbert 
5268fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5269fd32119bSDouglas Gilbert 				   struct scsi_cmnd *scp)
5270c2248fc9SDouglas Gilbert {
5271c2248fc9SDouglas Gilbert 	u8 sdeb_i;
5272c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
5273c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
5274c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
5275c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
5276c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
5277c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5278c2248fc9SDouglas Gilbert 	int k, na;
5279c2248fc9SDouglas Gilbert 	int errsts = 0;
5280c2248fc9SDouglas Gilbert 	u32 flags;
5281c2248fc9SDouglas Gilbert 	u16 sa;
5282c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
5283c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
5284c2248fc9SDouglas Gilbert 
5285c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
5286c4837394SDouglas Gilbert 	if (sdebug_statistics)
5287c4837394SDouglas Gilbert 		atomic_inc(&sdebug_cmnd_count);
5288f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_verbose &&
5289f46eb0e9SDouglas Gilbert 		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
5290c2248fc9SDouglas Gilbert 		char b[120];
5291c2248fc9SDouglas Gilbert 		int n, len, sb;
5292c2248fc9SDouglas Gilbert 
5293c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
5294c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
5295c2248fc9SDouglas Gilbert 		if (len > 32)
5296c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
5297c2248fc9SDouglas Gilbert 		else {
5298c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
5299c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
5300c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
5301c2248fc9SDouglas Gilbert 		}
5302c4837394SDouglas Gilbert 		if (sdebug_mq_active)
5303c4837394SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n",
5304c4837394SDouglas Gilbert 				    my_name, blk_mq_unique_tag(scp->request),
5305c4837394SDouglas Gilbert 				    b);
5306c4837394SDouglas Gilbert 		else
5307c4837394SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name,
5308c4837394SDouglas Gilbert 				    b);
5309c2248fc9SDouglas Gilbert 	}
531034d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
5311f46eb0e9SDouglas Gilbert 	if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5312f46eb0e9SDouglas Gilbert 		goto err_out;
5313c2248fc9SDouglas Gilbert 
5314c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
5315c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
5316c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
5317f46eb0e9SDouglas Gilbert 	if (unlikely(!devip)) {
5318f46eb0e9SDouglas Gilbert 		devip = find_build_dev_info(sdp);
5319c2248fc9SDouglas Gilbert 		if (NULL == devip)
5320f46eb0e9SDouglas Gilbert 			goto err_out;
5321c2248fc9SDouglas Gilbert 	}
5322c2248fc9SDouglas Gilbert 	na = oip->num_attached;
5323c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
5324c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
5325c2248fc9SDouglas Gilbert 		r_oip = oip;
5326c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
5327c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
5328c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
5329c2248fc9SDouglas Gilbert 			else
5330c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
5331c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5332c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
5333c2248fc9SDouglas Gilbert 					break;
5334c2248fc9SDouglas Gilbert 			}
5335c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
5336c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5337c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
5338c2248fc9SDouglas Gilbert 					break;
5339c2248fc9SDouglas Gilbert 			}
5340c2248fc9SDouglas Gilbert 		}
5341c2248fc9SDouglas Gilbert 		if (k > na) {
5342c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
5343c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5344c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
5345c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5346c2248fc9SDouglas Gilbert 			else
5347c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
5348c2248fc9SDouglas Gilbert 			goto check_cond;
5349c2248fc9SDouglas Gilbert 		}
5350c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
5351c2248fc9SDouglas Gilbert 	flags = oip->flags;
5352f46eb0e9SDouglas Gilbert 	if (unlikely(F_INV_OP & flags)) {
5353c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5354c2248fc9SDouglas Gilbert 		goto check_cond;
5355c2248fc9SDouglas Gilbert 	}
5356f46eb0e9SDouglas Gilbert 	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
5357773642d9SDouglas Gilbert 		if (sdebug_verbose)
5358773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5359773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
5360c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5361c2248fc9SDouglas Gilbert 		goto check_cond;
5362c2248fc9SDouglas Gilbert 	}
5363f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
5364c2248fc9SDouglas Gilbert 		u8 rem;
5365c2248fc9SDouglas Gilbert 		int j;
5366c2248fc9SDouglas Gilbert 
5367c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5368c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
5369c2248fc9SDouglas Gilbert 			if (rem) {
5370c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
5371c2248fc9SDouglas Gilbert 					if (0x80 & rem)
5372c2248fc9SDouglas Gilbert 						break;
5373c2248fc9SDouglas Gilbert 				}
5374c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5375c2248fc9SDouglas Gilbert 				goto check_cond;
5376c2248fc9SDouglas Gilbert 			}
5377c2248fc9SDouglas Gilbert 		}
5378c2248fc9SDouglas Gilbert 	}
5379f46eb0e9SDouglas Gilbert 	if (unlikely(!(F_SKIP_UA & flags) &&
5380b01f6f83SDouglas Gilbert 		     find_first_bit(devip->uas_bm,
5381b01f6f83SDouglas Gilbert 				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
5382f46eb0e9SDouglas Gilbert 		errsts = make_ua(scp, devip);
5383c2248fc9SDouglas Gilbert 		if (errsts)
5384c2248fc9SDouglas Gilbert 			goto check_cond;
5385c2248fc9SDouglas Gilbert 	}
5386c4837394SDouglas Gilbert 	if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
5387c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
5388773642d9SDouglas Gilbert 		if (sdebug_verbose)
5389c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5390c2248fc9SDouglas Gilbert 				    "%s\n", my_name, "initializing command "
5391c2248fc9SDouglas Gilbert 				    "required");
5392c2248fc9SDouglas Gilbert 		errsts = check_condition_result;
5393c2248fc9SDouglas Gilbert 		goto fini;
5394c2248fc9SDouglas Gilbert 	}
5395773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
5396c2248fc9SDouglas Gilbert 		goto fini;
5397f46eb0e9SDouglas Gilbert 	if (unlikely(sdebug_every_nth)) {
5398c4837394SDouglas Gilbert 		if (fake_timeout(scp))
5399c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
5400c2248fc9SDouglas Gilbert 	}
5401f46eb0e9SDouglas Gilbert 	if (likely(oip->pfp))
5402f46eb0e9SDouglas Gilbert 		errsts = oip->pfp(scp, devip);	/* calls a resp_* function */
5403c2248fc9SDouglas Gilbert 	else if (r_pfp)	/* if leaf function ptr NULL, try the root's */
5404c2248fc9SDouglas Gilbert 		errsts = r_pfp(scp, devip);
5405c2248fc9SDouglas Gilbert 
5406c2248fc9SDouglas Gilbert fini:
5407c2248fc9SDouglas Gilbert 	return schedule_resp(scp, devip, errsts,
5408c2206098SDouglas Gilbert 			     ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay));
5409c2248fc9SDouglas Gilbert check_cond:
5410c2248fc9SDouglas Gilbert 	return schedule_resp(scp, devip, check_condition_result, 0);
5411f46eb0e9SDouglas Gilbert err_out:
5412f46eb0e9SDouglas Gilbert 	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0);
5413c2248fc9SDouglas Gilbert }
5414c2248fc9SDouglas Gilbert 
54159e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
5416c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
5417c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
54189e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
54199e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
54209e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
54219e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
54229e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
54239e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
54249e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
5425185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
5426cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
54279e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
54289e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
5429cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
5430cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
54319e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
5432c4837394SDouglas Gilbert 	.can_queue =		SDEBUG_CANQUEUE,
54339e603ca0SFUJITA Tomonori 	.this_id =		7,
543465e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
5435cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
54366bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
54379e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
54389e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
5439c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
54409e603ca0SFUJITA Tomonori };
54419e603ca0SFUJITA Tomonori 
54421da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev)
54431da177e4SLinus Torvalds {
54441da177e4SLinus Torvalds 	int error = 0;
54451da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
54461da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
5447f46eb0e9SDouglas Gilbert 	int hprot;
54481da177e4SLinus Torvalds 
54491da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
54501da177e4SLinus Torvalds 
5451773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
5452773642d9SDouglas Gilbert 	if (sdebug_clustering)
54530759c666SAkinobu Mita 		sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
54541da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
54551da177e4SLinus Torvalds 	if (NULL == hpnt) {
5456c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
54571da177e4SLinus Torvalds 		error = -ENODEV;
54581da177e4SLinus Torvalds 		return error;
54591da177e4SLinus Torvalds 	}
5460c4837394SDouglas Gilbert 	if (submit_queues > nr_cpu_ids) {
5461c4837394SDouglas Gilbert 		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%d\n",
5462c4837394SDouglas Gilbert 			my_name, submit_queues, nr_cpu_ids);
5463c4837394SDouglas Gilbert 		submit_queues = nr_cpu_ids;
5464c4837394SDouglas Gilbert 	}
5465c4837394SDouglas Gilbert 	/* Decide whether to tell scsi subsystem that we want mq */
5466c4837394SDouglas Gilbert 	/* Following should give the same answer for each host */
5467c4837394SDouglas Gilbert 	sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1);
5468c4837394SDouglas Gilbert 	if (sdebug_mq_active)
5469c4837394SDouglas Gilbert 		hpnt->nr_hw_queues = submit_queues;
54701da177e4SLinus Torvalds 
54711da177e4SLinus Torvalds         sdbg_host->shost = hpnt;
54721da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
5473773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5474773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
54751da177e4SLinus Torvalds 	else
5476773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
5477773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
5478f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
54791da177e4SLinus Torvalds 
5480f46eb0e9SDouglas Gilbert 	hprot = 0;
5481c6a44287SMartin K. Petersen 
5482773642d9SDouglas Gilbert 	switch (sdebug_dif) {
5483c6a44287SMartin K. Petersen 
54848475c811SChristoph Hellwig 	case T10_PI_TYPE1_PROTECTION:
5485f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE1_PROTECTION;
5486773642d9SDouglas Gilbert 		if (sdebug_dix)
5487f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE1_PROTECTION;
5488c6a44287SMartin K. Petersen 		break;
5489c6a44287SMartin K. Petersen 
54908475c811SChristoph Hellwig 	case T10_PI_TYPE2_PROTECTION:
5491f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE2_PROTECTION;
5492773642d9SDouglas Gilbert 		if (sdebug_dix)
5493f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE2_PROTECTION;
5494c6a44287SMartin K. Petersen 		break;
5495c6a44287SMartin K. Petersen 
54968475c811SChristoph Hellwig 	case T10_PI_TYPE3_PROTECTION:
5497f46eb0e9SDouglas Gilbert 		hprot = SHOST_DIF_TYPE3_PROTECTION;
5498773642d9SDouglas Gilbert 		if (sdebug_dix)
5499f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE3_PROTECTION;
5500c6a44287SMartin K. Petersen 		break;
5501c6a44287SMartin K. Petersen 
5502c6a44287SMartin K. Petersen 	default:
5503773642d9SDouglas Gilbert 		if (sdebug_dix)
5504f46eb0e9SDouglas Gilbert 			hprot |= SHOST_DIX_TYPE0_PROTECTION;
5505c6a44287SMartin K. Petersen 		break;
5506c6a44287SMartin K. Petersen 	}
5507c6a44287SMartin K. Petersen 
5508f46eb0e9SDouglas Gilbert 	scsi_host_set_prot(hpnt, hprot);
5509c6a44287SMartin K. Petersen 
5510f46eb0e9SDouglas Gilbert 	if (have_dif_prot || sdebug_dix)
5511c1287970STomas Winkler 		pr_info("host protection%s%s%s%s%s%s%s\n",
5512f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5513f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5514f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5515f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5516f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5517f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5518f46eb0e9SDouglas Gilbert 			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
5519c6a44287SMartin K. Petersen 
5520773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
5521c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5522c6a44287SMartin K. Petersen 	else
5523c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5524c6a44287SMartin K. Petersen 
5525773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5526773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
5527c4837394SDouglas Gilbert 	if (sdebug_every_nth)	/* need stats counters for every_nth */
5528c4837394SDouglas Gilbert 		sdebug_statistics = true;
55291da177e4SLinus Torvalds         error = scsi_add_host(hpnt, &sdbg_host->dev);
55301da177e4SLinus Torvalds         if (error) {
5531c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
55321da177e4SLinus Torvalds                 error = -ENODEV;
55331da177e4SLinus Torvalds 		scsi_host_put(hpnt);
55341da177e4SLinus Torvalds         } else
55351da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
55361da177e4SLinus Torvalds 
55371da177e4SLinus Torvalds 	return error;
55381da177e4SLinus Torvalds }
55391da177e4SLinus Torvalds 
55401da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev)
55411da177e4SLinus Torvalds {
55421da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
55438b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
55441da177e4SLinus Torvalds 
55451da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
55461da177e4SLinus Torvalds 
55471da177e4SLinus Torvalds 	if (!sdbg_host) {
5548c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
55491da177e4SLinus Torvalds 		return -ENODEV;
55501da177e4SLinus Torvalds 	}
55511da177e4SLinus Torvalds 
55521da177e4SLinus Torvalds         scsi_remove_host(sdbg_host->shost);
55531da177e4SLinus Torvalds 
55548b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
55558b40228fSFUJITA Tomonori 				 dev_list) {
55561da177e4SLinus Torvalds                 list_del(&sdbg_devinfo->dev_list);
55571da177e4SLinus Torvalds                 kfree(sdbg_devinfo);
55581da177e4SLinus Torvalds         }
55591da177e4SLinus Torvalds 
55601da177e4SLinus Torvalds         scsi_host_put(sdbg_host->shost);
55611da177e4SLinus Torvalds         return 0;
55621da177e4SLinus Torvalds }
55631da177e4SLinus Torvalds 
55648dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
55658dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
55661da177e4SLinus Torvalds {
55678dea0d02SFUJITA Tomonori 	return 1;
55688dea0d02SFUJITA Tomonori }
55691da177e4SLinus Torvalds 
55708dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
55718dea0d02SFUJITA Tomonori 	.name = "pseudo",
55728dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
55738dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
55748dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
557582069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
55768dea0d02SFUJITA Tomonori };
5577