xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 65e8617f)
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  *
91da177e4SLinus Torvalds  *  This version is more generic, simulating a variable number of disk
1023183910SDouglas Gilbert  *  (or disk like devices) sharing a common amount of RAM. To be more
1123183910SDouglas Gilbert  *  realistic, the simulated devices have the transport attributes of
1223183910SDouglas Gilbert  *  SAS disks.
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  *
1578d4e5a0SDouglas Gilbert  *  For documentation see http://sg.danny.cz/sg/sdebug26.html
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  *   D. Gilbert (dpg) work for Magneto-Optical device test [20010421]
181da177e4SLinus Torvalds  *   dpg: work for devfs large number of disks [20010809]
191da177e4SLinus Torvalds  *        forked for lk 2.5 series [20011216, 20020101]
201da177e4SLinus Torvalds  *        use vmalloc() more inquiry+mode_sense [20020302]
211da177e4SLinus Torvalds  *        add timers for delayed responses [20020721]
221da177e4SLinus Torvalds  *   Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031]
231da177e4SLinus Torvalds  *   Mike Anderson <andmike@us.ibm.com> sysfs work [20021118]
241da177e4SLinus Torvalds  *   dpg: change style of boot options to "scsi_debug.num_tgts=2" and
251da177e4SLinus Torvalds  *        module options to "modprobe scsi_debug num_tgts=2" [20021221]
261da177e4SLinus Torvalds  */
271da177e4SLinus Torvalds 
28c1287970STomas Winkler 
29c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
30c1287970STomas Winkler 
311da177e4SLinus Torvalds #include <linux/module.h>
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds #include <linux/kernel.h>
341da177e4SLinus Torvalds #include <linux/errno.h>
351da177e4SLinus Torvalds #include <linux/timer.h>
365a0e3ad6STejun Heo #include <linux/slab.h>
371da177e4SLinus Torvalds #include <linux/types.h>
381da177e4SLinus Torvalds #include <linux/string.h>
391da177e4SLinus Torvalds #include <linux/genhd.h>
401da177e4SLinus Torvalds #include <linux/fs.h>
411da177e4SLinus Torvalds #include <linux/init.h>
421da177e4SLinus Torvalds #include <linux/proc_fs.h>
431da177e4SLinus Torvalds #include <linux/vmalloc.h>
441da177e4SLinus Torvalds #include <linux/moduleparam.h>
45852e034dSJens Axboe #include <linux/scatterlist.h>
461da177e4SLinus Torvalds #include <linux/blkdev.h>
47c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h>
48cbf67842SDouglas Gilbert #include <linux/spinlock.h>
49cbf67842SDouglas Gilbert #include <linux/interrupt.h>
50cbf67842SDouglas Gilbert #include <linux/atomic.h>
51cbf67842SDouglas Gilbert #include <linux/hrtimer.h>
52c6a44287SMartin K. Petersen 
53c6a44287SMartin K. Petersen #include <net/checksum.h>
549ff26eefSFUJITA Tomonori 
5544d92694SMartin K. Petersen #include <asm/unaligned.h>
5644d92694SMartin K. Petersen 
579ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
589ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
599ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
601da177e4SLinus Torvalds #include <scsi/scsi_host.h>
611da177e4SLinus Torvalds #include <scsi/scsicam.h>
62a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
63cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h>
64395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
651da177e4SLinus Torvalds 
66c6a44287SMartin K. Petersen #include "sd.h"
671da177e4SLinus Torvalds #include "scsi_logging.h"
681da177e4SLinus Torvalds 
6922017ed2SDouglas Gilbert #define SCSI_DEBUG_VERSION "1.85"
7022017ed2SDouglas Gilbert static const char *scsi_debug_version_date = "20141022";
71cbf67842SDouglas Gilbert 
72cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
731da177e4SLinus Torvalds 
746f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
75c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
76c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
77c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
781da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
79c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
801da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
8122017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
821da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
83c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
84cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
85cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
8619c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
8719c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8822017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8922017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
90cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
91cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
92cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
9322017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9
941da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
956f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
96c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
97c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
9822017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d
99acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1	/* with TARGET_CHANGED_ASC */
100acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
1011da177e4SLinus Torvalds 
1026f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
1036f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
1046f3cbf55SDouglas Gilbert 
1051da177e4SLinus Torvalds 
1061da177e4SLinus Torvalds /* Default values for driver parameters */
1071da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1081da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1091da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1101da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1111da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1121da177e4SLinus Torvalds  */
1135b94e232SMartin K. Petersen #define DEF_ATO 1
114cbf67842SDouglas Gilbert #define DEF_DELAY   1		/* if > 0 unit is a jiffy */
1151da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1165b94e232SMartin K. Petersen #define DEF_DIF 0
1175b94e232SMartin K. Petersen #define DEF_DIX 0
1185b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1191da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1205b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1215b94e232SMartin K. Petersen #define DEF_GUARD 0
122cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1235b94e232SMartin K. Petersen #define DEF_LBPU 0
1245b94e232SMartin K. Petersen #define DEF_LBPWS 0
1255b94e232SMartin K. Petersen #define DEF_LBPWS10 0
126be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1275b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
128cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1295b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1301da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1311da177e4SLinus Torvalds #define DEF_OPTS   0
13232c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1335b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
1345b94e232SMartin K. Petersen #define DEF_PTYPE   0
135d986788bSMartin Pitt #define DEF_REMOVABLE false
136e46b0344SDouglas Gilbert #define DEF_SCSI_LEVEL   6    /* INQUIRY, byte2 [6->SPC-4] */
1375b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1385b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1395b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1406014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1416014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1425b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1435b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1445b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
145c2248fc9SDouglas Gilbert #define DEF_STRICT 0
146cbf67842SDouglas Gilbert #define DELAY_OVERRIDDEN -9999
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */
1491da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE   1
1501da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR   2
1511da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT   4
1521da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR   8
1536f3cbf55SDouglas Gilbert #define SCSI_DEBUG_OPT_TRANSPORT_ERR   16
154c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIF_ERR   32
155c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIX_ERR   64
15618a4d0a2SMartin K. Petersen #define SCSI_DEBUG_OPT_MAC_TIMEOUT  128
157cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_SHORT_TRANSFER	0x100
158cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_Q_NOISE	0x200
159cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_ALL_TSF	0x400
160cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_RARE_TSF	0x800
161cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_N_WCE	0x1000
162cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_RESET_NOISE 0x2000
163cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_NO_CDB_NOISE 0x4000
164cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_ALL_NOISE (0x1 | 0x200 | 0x2000)
1651da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
1661da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1671da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1681da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1696f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1706f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1711da177e4SLinus Torvalds  *
1721da177e4SLinus Torvalds  * When "every_nth" < 0 then after "- every_nth" commands:
1731da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1741da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1751da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1766f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1776f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1781da177e4SLinus Torvalds  * This will continue until some other action occurs (e.g. the user
1791da177e4SLinus Torvalds  * writing a new value (other than -1 or 1) to every_nth via sysfs).
1801da177e4SLinus Torvalds  */
1811da177e4SLinus Torvalds 
182cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs)are returned in
183cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
184cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
185cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
186cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
187cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1
188cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2
1890d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3
19019c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4
191acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5	/* simulate firmware change */
192acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
193acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7
194cbf67842SDouglas Gilbert 
195cbf67842SDouglas Gilbert /* for check_readiness() */
196c2248fc9SDouglas Gilbert #define UAS_ONLY 1	/* check for UAs only */
197c2248fc9SDouglas Gilbert #define UAS_TUR 0	/* if no UAs then check if media access possible */
198cbf67842SDouglas Gilbert 
1991da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
2001da177e4SLinus Torvalds  * sector on read commands: */
2011da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
20232f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
2051da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
2061da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
2071da177e4SLinus Torvalds 
208cbf67842SDouglas Gilbert /* SCSI_DEBUG_CANQUEUE is the maximum number of commands that can be queued
209cbf67842SDouglas Gilbert  * (for response) at one time. Can be reduced by max_queue option. Command
210cbf67842SDouglas Gilbert  * responses are not queued when delay=0 and ndelay=0. The per-device
211cbf67842SDouglas Gilbert  * DEF_CMD_PER_LUN can be changed via sysfs:
212cbf67842SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth but cannot exceed
213cbf67842SDouglas Gilbert  * SCSI_DEBUG_CANQUEUE. */
214cbf67842SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE_WORDS  9	/* a WORD is bits in a long */
215cbf67842SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE  (SCSI_DEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
216cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN  255
217cbf67842SDouglas Gilbert 
218cbf67842SDouglas Gilbert #if DEF_CMD_PER_LUN > SCSI_DEBUG_CANQUEUE
219cbf67842SDouglas Gilbert #warning "Expect DEF_CMD_PER_LUN <= SCSI_DEBUG_CANQUEUE"
220cbf67842SDouglas Gilbert #endif
22178d4e5a0SDouglas Gilbert 
222c2248fc9SDouglas Gilbert /* SCSI opcodes (first byte of cdb) mapped onto these indexes */
223c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
224c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
225c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
226c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
227c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
228c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
229c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
230c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
231c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
232c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
233c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
234c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
235c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
236c2248fc9SDouglas Gilbert 	SDEB_I_SERV_ACT_IN = 12,	/* 12, 16 */
237c2248fc9SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT = 13,	/* 12, 16 */
238c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
239c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
240c2248fc9SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* 10 only */
241c2248fc9SDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,
242c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
243c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
244c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
245c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
246c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
247c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
248c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
249c2248fc9SDouglas Gilbert 	SDEB_I_XDWRITEREAD = 25,	/* 10 only */
250c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_BUFFER = 26,
251c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_SAME = 27,		/* 10, 16 */
252c2248fc9SDouglas Gilbert 	SDEB_I_SYNC_CACHE = 28,		/* 10 only */
253c2248fc9SDouglas Gilbert 	SDEB_I_COMP_WRITE = 29,
254c2248fc9SDouglas Gilbert 	SDEB_I_LAST_ELEMENT = 30,	/* keep this last */
255c2248fc9SDouglas Gilbert };
256c2248fc9SDouglas Gilbert 
257c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
258c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
259c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
260c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
261c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
262c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
263c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
264c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
265c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
266c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
267c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
268c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
269c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
270c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
271c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
272c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
273c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
274c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
275c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
276c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
277c2248fc9SDouglas Gilbert /* 0x60; 0x60->0x7d are reserved */
278c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
279c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
280c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
281c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
282c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
283c2248fc9SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
284c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
285c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT,
286c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
287c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
288c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
289c2248fc9SDouglas Gilbert 	SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN,
290c2248fc9SDouglas Gilbert 	     0, 0, 0, 0,
291c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
292c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
293c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
294c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
295c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
296c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
297c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
298c2248fc9SDouglas Gilbert };
299c2248fc9SDouglas Gilbert 
300c2248fc9SDouglas Gilbert #define F_D_IN			1
301c2248fc9SDouglas Gilbert #define F_D_OUT			2
302c2248fc9SDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
303c2248fc9SDouglas Gilbert #define F_D_UNKN		8
304c2248fc9SDouglas Gilbert #define F_RL_WLUN_OK		0x10
305c2248fc9SDouglas Gilbert #define F_SKIP_UA		0x20
306c2248fc9SDouglas Gilbert #define F_DELAY_OVERR		0x40
307c2248fc9SDouglas Gilbert #define F_SA_LOW		0x80	/* cdb byte 1, bits 4 to 0 */
308c2248fc9SDouglas Gilbert #define F_SA_HIGH		0x100	/* as used by variable length cdbs */
309c2248fc9SDouglas Gilbert #define F_INV_OP		0x200
310c2248fc9SDouglas Gilbert #define F_FAKE_RW		0x400
311c2248fc9SDouglas Gilbert #define F_M_ACCESS		0x800	/* media access */
312c2248fc9SDouglas Gilbert 
313c2248fc9SDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
314c2248fc9SDouglas Gilbert #define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW)
315c2248fc9SDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
316c2248fc9SDouglas Gilbert 
317c2248fc9SDouglas Gilbert struct sdebug_dev_info;
318c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
319c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
320c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
321c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
322c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
323c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
324c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
325c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
326c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
327c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
328c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
329c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
330c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
331c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
33238d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
33338d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
334c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
335c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
336c2248fc9SDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
33738d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
338acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
339c2248fc9SDouglas Gilbert 
340c2248fc9SDouglas Gilbert struct opcode_info_t {
341c2248fc9SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff
342c2248fc9SDouglas Gilbert 				 * for terminating element */
343c2248fc9SDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
344c2248fc9SDouglas Gilbert 	u16 sa;			/* service action */
345c2248fc9SDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
346c2248fc9SDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
347c2248fc9SDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
348c2248fc9SDouglas Gilbert 	u8 len_mask[16];	/* len=len_mask[0], then mask for cdb[1]... */
349c2248fc9SDouglas Gilbert 				/* ignore cdb bytes after position 15 */
350c2248fc9SDouglas Gilbert };
351c2248fc9SDouglas Gilbert 
352c2248fc9SDouglas Gilbert static const struct opcode_info_t msense_iarr[1] = {
353c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
354c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
355c2248fc9SDouglas Gilbert };
356c2248fc9SDouglas Gilbert 
357c2248fc9SDouglas Gilbert static const struct opcode_info_t mselect_iarr[1] = {
358c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
359c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
360c2248fc9SDouglas Gilbert };
361c2248fc9SDouglas Gilbert 
362c2248fc9SDouglas Gilbert static const struct opcode_info_t read_iarr[3] = {
363c2248fc9SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */
364c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
365c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
366c2248fc9SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */
367c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
368c2248fc9SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */
369c2248fc9SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
370c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
371c2248fc9SDouglas Gilbert };
372c2248fc9SDouglas Gilbert 
373c2248fc9SDouglas Gilbert static const struct opcode_info_t write_iarr[3] = {
374c2248fc9SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,   /* 10 */
375c2248fc9SDouglas Gilbert 	    {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
376c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
377c2248fc9SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,    /* 6 */
378c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
379c2248fc9SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,   /* 12 */
380c2248fc9SDouglas Gilbert 	    {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
381c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
382c2248fc9SDouglas Gilbert };
383c2248fc9SDouglas Gilbert 
384c2248fc9SDouglas Gilbert static const struct opcode_info_t sa_in_iarr[1] = {
385c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
386c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
387c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },
388c2248fc9SDouglas Gilbert };
389c2248fc9SDouglas Gilbert 
390c2248fc9SDouglas Gilbert static const struct opcode_info_t vl_iarr[1] = {	/* VARIABLE LENGTH */
391c2248fc9SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0,
392c2248fc9SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa,
393c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
394c2248fc9SDouglas Gilbert };
395c2248fc9SDouglas Gilbert 
396c2248fc9SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[2] = {
39738d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
398c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
399c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
40038d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
401c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
402c2248fc9SDouglas Gilbert 	     0, 0} },
403c2248fc9SDouglas Gilbert };
404c2248fc9SDouglas Gilbert 
405c2248fc9SDouglas Gilbert static const struct opcode_info_t write_same_iarr[1] = {
406c2248fc9SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL,
407c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
408c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x1f, 0xc7} },
409c2248fc9SDouglas Gilbert };
410c2248fc9SDouglas Gilbert 
411c2248fc9SDouglas Gilbert static const struct opcode_info_t reserve_iarr[1] = {
412c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,	/* RESERVE(6) */
413c2248fc9SDouglas Gilbert 	    {6,  0x1f, 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 release_iarr[1] = {
417c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,	/* RELEASE(6) */
418c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
419c2248fc9SDouglas Gilbert };
420c2248fc9SDouglas Gilbert 
421c2248fc9SDouglas Gilbert 
422c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
423c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
424c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
425c2248fc9SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
426c2248fc9SDouglas Gilbert /* 0 */
427c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,
428c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
429c2248fc9SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL,
430c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
431c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
432c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
433c2248fc9SDouglas Gilbert 	     0, 0} },
434c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
435c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
436c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
437c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
438c2248fc9SDouglas Gilbert 	{1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr,
439c2248fc9SDouglas Gilbert 	    {10,  0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
440c2248fc9SDouglas Gilbert 	     0} },
441c2248fc9SDouglas Gilbert 	{1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr,
442c2248fc9SDouglas Gilbert 	    {10,  0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
443c2248fc9SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,
444c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
445c2248fc9SDouglas Gilbert 	     0, 0, 0} },
446c2248fc9SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,
447c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
448c2248fc9SDouglas Gilbert 	     0, 0} },
449c2248fc9SDouglas Gilbert 	{3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr,
450c2248fc9SDouglas Gilbert 	    {16,  0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
451c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x9f, 0xc7} },		/* READ(16) */
452c2248fc9SDouglas Gilbert /* 10 */
453c2248fc9SDouglas Gilbert 	{3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr,
454c2248fc9SDouglas Gilbert 	    {16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
455c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x9f, 0xc7} },		/* WRITE(16) */
456c2248fc9SDouglas Gilbert 	{0, 0x1b, 0, 0, resp_start_stop, NULL,		/* START STOP UNIT */
457c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
458c2248fc9SDouglas Gilbert 	{1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr,
459c2248fc9SDouglas Gilbert 	    {16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
460c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x1, 0xc7} },	/* READ CAPACITY(16) */
461c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */
462c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
463c2248fc9SDouglas Gilbert 	{2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr,
464c2248fc9SDouglas Gilbert 	    {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0,
465c2248fc9SDouglas Gilbert 	     0} },
466c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
467c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
468f7f9f26bSDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */
469f7f9f26bSDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
470f7f9f26bSDouglas Gilbert 	     0, 0, 0, 0, 0, 0} },
471c2248fc9SDouglas Gilbert 	{1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0,
472c2248fc9SDouglas Gilbert 	    vl_iarr, {32,  0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0,
473c2248fc9SDouglas Gilbert 		      0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */
474c2248fc9SDouglas Gilbert 	{1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */
475c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
476c2248fc9SDouglas Gilbert 	     0} },
477c2248fc9SDouglas Gilbert 	{1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */
478c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
479c2248fc9SDouglas Gilbert 	     0} },
480c2248fc9SDouglas Gilbert /* 20 */
481f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
482f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
483c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
484c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
485c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
486c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
487c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
488c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
489c2248fc9SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */
490c2248fc9SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
491c2248fc9SDouglas Gilbert 	{0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10,
492c2248fc9SDouglas Gilbert 	    NULL, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7,
493c2248fc9SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
494acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
495acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
496acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
497c2248fc9SDouglas Gilbert 	{1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10,
498c2248fc9SDouglas Gilbert 	    write_same_iarr, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff,
499c2248fc9SDouglas Gilbert 			      0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
500c2248fc9SDouglas Gilbert 	{0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */
501c2248fc9SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
502c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
50338d5c833SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL,
504c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
505c2248fc9SDouglas Gilbert 	     0, 0xff, 0x1f, 0xc7} },		/* COMPARE AND WRITE */
506c2248fc9SDouglas Gilbert 
507c2248fc9SDouglas Gilbert /* 30 */
508c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
509c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
510c2248fc9SDouglas Gilbert };
511c2248fc9SDouglas Gilbert 
512817fd66bSDouglas Gilbert struct sdebug_scmd_extra_t {
513817fd66bSDouglas Gilbert 	bool inj_recovered;
514817fd66bSDouglas Gilbert 	bool inj_transport;
515817fd66bSDouglas Gilbert 	bool inj_dif;
516817fd66bSDouglas Gilbert 	bool inj_dix;
517817fd66bSDouglas Gilbert 	bool inj_short;
518817fd66bSDouglas Gilbert };
519817fd66bSDouglas Gilbert 
5201da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST;
5215b94e232SMartin K. Petersen static int scsi_debug_ato = DEF_ATO;
5221da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY;
5231da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
5245b94e232SMartin K. Petersen static int scsi_debug_dif = DEF_DIF;
5255b94e232SMartin K. Petersen static int scsi_debug_dix = DEF_DIX;
5265b94e232SMartin K. Petersen static int scsi_debug_dsense = DEF_D_SENSE;
5271da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH;
5285b94e232SMartin K. Petersen static int scsi_debug_fake_rw = DEF_FAKE_RW;
52968aee7baSAkinobu Mita static unsigned int scsi_debug_guard = DEF_GUARD;
5305b94e232SMartin K. Petersen static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
5311da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS;
53278d4e5a0SDouglas Gilbert static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE;
533cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
534cbf67842SDouglas Gilbert static int scsi_debug_ndelay = DEF_NDELAY;
535c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
5365b94e232SMartin K. Petersen static int scsi_debug_no_uld = 0;
5375b94e232SMartin K. Petersen static int scsi_debug_num_parts = DEF_NUM_PARTS;
5385b94e232SMartin K. Petersen static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
539e308b3d1SMartin K. Petersen static int scsi_debug_opt_blks = DEF_OPT_BLKS;
5405b94e232SMartin K. Petersen static int scsi_debug_opts = DEF_OPTS;
5415b94e232SMartin K. Petersen static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
5425b94e232SMartin K. Petersen static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
5435b94e232SMartin K. Petersen static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
5445b94e232SMartin K. Petersen static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
5455b94e232SMartin K. Petersen static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
5465b94e232SMartin K. Petersen static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
5475b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpu = DEF_LBPU;
5485b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws = DEF_LBPWS;
5495b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10;
550be1dd78dSEric Sandeen static unsigned int scsi_debug_lbprz = DEF_LBPRZ;
5516014759cSMartin K. Petersen static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
5525b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
5535b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
5545b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
5555b94e232SMartin K. Petersen static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH;
556d986788bSMartin Pitt static bool scsi_debug_removable = DEF_REMOVABLE;
5570759c666SAkinobu Mita static bool scsi_debug_clustering;
558cbf67842SDouglas Gilbert static bool scsi_debug_host_lock = DEF_HOST_LOCK;
559c2248fc9SDouglas Gilbert static bool scsi_debug_strict = DEF_STRICT;
560817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
5611da177e4SLinus Torvalds 
562cbf67842SDouglas Gilbert static atomic_t sdebug_cmnd_count;
563cbf67842SDouglas Gilbert static atomic_t sdebug_completions;
564cbf67842SDouglas Gilbert static atomic_t sdebug_a_tsf;		/* counter of 'almost' TSFs */
5651da177e4SLinus Torvalds 
5661da177e4SLinus Torvalds #define DEV_READONLY(TGT)      (0)
5671da177e4SLinus Torvalds 
568c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
5691da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
5701da177e4SLinus Torvalds 
5711da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
5721da177e4SLinus Torvalds    may still need them */
5731da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
5741da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
5751da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
5761da177e4SLinus Torvalds 
5771da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4
5781da177e4SLinus Torvalds 
579395cef03SMartin K. Petersen #define SCSI_DEBUG_MAX_CMD_LEN 32
5809e603ca0SFUJITA Tomonori 
5815b94e232SMartin K. Petersen static unsigned int scsi_debug_lbp(void)
5825b94e232SMartin K. Petersen {
583cbf67842SDouglas Gilbert 	return ((0 == scsi_debug_fake_rw) &&
584cbf67842SDouglas Gilbert 		(scsi_debug_lbpu | scsi_debug_lbpws | scsi_debug_lbpws10));
5855b94e232SMartin K. Petersen }
5865b94e232SMartin K. Petersen 
5871da177e4SLinus Torvalds struct sdebug_dev_info {
5881da177e4SLinus Torvalds 	struct list_head dev_list;
5891da177e4SLinus Torvalds 	unsigned int channel;
5901da177e4SLinus Torvalds 	unsigned int target;
5919cb78c16SHannes Reinecke 	u64 lun;
5921da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
593cbf67842SDouglas Gilbert 	unsigned long uas_bm[1];
594cbf67842SDouglas Gilbert 	atomic_t num_in_q;
595c2248fc9SDouglas Gilbert 	char stopped;		/* TODO: should be atomic */
596c2248fc9SDouglas Gilbert 	bool used;
5971da177e4SLinus Torvalds };
5981da177e4SLinus Torvalds 
5991da177e4SLinus Torvalds struct sdebug_host_info {
6001da177e4SLinus Torvalds 	struct list_head host_list;
6011da177e4SLinus Torvalds 	struct Scsi_Host *shost;
6021da177e4SLinus Torvalds 	struct device dev;
6031da177e4SLinus Torvalds 	struct list_head dev_info_list;
6041da177e4SLinus Torvalds };
6051da177e4SLinus Torvalds 
6061da177e4SLinus Torvalds #define to_sdebug_host(d)	\
6071da177e4SLinus Torvalds 	container_of(d, struct sdebug_host_info, dev)
6081da177e4SLinus Torvalds 
6091da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
6101da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
6111da177e4SLinus Torvalds 
612cbf67842SDouglas Gilbert 
613cbf67842SDouglas Gilbert struct sdebug_hrtimer {		/* ... is derived from hrtimer */
614cbf67842SDouglas Gilbert 	struct hrtimer hrt;	/* must be first element */
615cbf67842SDouglas Gilbert 	int qa_indx;
616cbf67842SDouglas Gilbert };
6171da177e4SLinus Torvalds 
6181da177e4SLinus Torvalds struct sdebug_queued_cmd {
619cbf67842SDouglas Gilbert 	/* in_use flagged by a bit in queued_in_use_bm[] */
620cbf67842SDouglas Gilbert 	struct timer_list *cmnd_timerp;
621cbf67842SDouglas Gilbert 	struct tasklet_struct *tletp;
622cbf67842SDouglas Gilbert 	struct sdebug_hrtimer *sd_hrtp;
6231da177e4SLinus Torvalds 	struct scsi_cmnd * a_cmnd;
6241da177e4SLinus Torvalds };
6251da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
626cbf67842SDouglas Gilbert static unsigned long queued_in_use_bm[SCSI_DEBUG_CANQUEUE_WORDS];
627cbf67842SDouglas Gilbert 
6281da177e4SLinus Torvalds 
6291da177e4SLinus Torvalds static unsigned char * fake_storep;	/* ramdisk storage */
630e18d8beaSAkinobu Mita static struct sd_dif_tuple *dif_storep;	/* protection info */
63144d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
6321da177e4SLinus Torvalds 
63344d92694SMartin K. Petersen static unsigned long map_size;
634cbf67842SDouglas Gilbert static int num_aborts;
635cbf67842SDouglas Gilbert static int num_dev_resets;
636cbf67842SDouglas Gilbert static int num_target_resets;
637cbf67842SDouglas Gilbert static int num_bus_resets;
638cbf67842SDouglas Gilbert static int num_host_resets;
639c6a44287SMartin K. Petersen static int dix_writes;
640c6a44287SMartin K. Petersen static int dix_reads;
641c6a44287SMartin K. Petersen static int dif_errors;
6421da177e4SLinus Torvalds 
6431da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock);
6441da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
6451da177e4SLinus Torvalds 
646cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
647cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
6481da177e4SLinus Torvalds 
6491da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
6501da177e4SLinus Torvalds 
6511da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
6521da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
6531da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
6541da177e4SLinus Torvalds };
6551da177e4SLinus Torvalds 
6561da177e4SLinus Torvalds static const int check_condition_result =
6571da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
6581da177e4SLinus Torvalds 
659c6a44287SMartin K. Petersen static const int illegal_condition_result =
660c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
661c6a44287SMartin K. Petersen 
662cbf67842SDouglas Gilbert static const int device_qfull_result =
663cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
664cbf67842SDouglas Gilbert 
665cbf67842SDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
666cbf67842SDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
667cbf67842SDouglas Gilbert 				     0, 0, 0, 0};
668c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
669c65b1445SDouglas Gilbert 				    0, 0, 0x2, 0x4b};
670c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
671c65b1445SDouglas Gilbert 			           0, 0, 0x0, 0x0};
672c65b1445SDouglas Gilbert 
67314faa944SAkinobu Mita static void *fake_store(unsigned long long lba)
67414faa944SAkinobu Mita {
67514faa944SAkinobu Mita 	lba = do_div(lba, sdebug_store_sectors);
67614faa944SAkinobu Mita 
67714faa944SAkinobu Mita 	return fake_storep + lba * scsi_debug_sector_size;
67814faa944SAkinobu Mita }
67914faa944SAkinobu Mita 
68014faa944SAkinobu Mita static struct sd_dif_tuple *dif_store(sector_t sector)
68114faa944SAkinobu Mita {
68249413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
68314faa944SAkinobu Mita 
68414faa944SAkinobu Mita 	return dif_storep + sector;
68514faa944SAkinobu Mita }
68614faa944SAkinobu Mita 
6871da177e4SLinus Torvalds static int sdebug_add_adapter(void);
6881da177e4SLinus Torvalds static void sdebug_remove_adapter(void);
6891da177e4SLinus Torvalds 
6908dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
6918dea0d02SFUJITA Tomonori {
6928dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
6938dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
6948dea0d02SFUJITA Tomonori 
6958dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
6968dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
6978dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
6988dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
6998dea0d02SFUJITA Tomonori 		    (scsi_debug_num_tgts > hpnt->this_id))
7008dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts + 1;
7018dea0d02SFUJITA Tomonori 		else
7028dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts;
7038dea0d02SFUJITA Tomonori 		/* scsi_debug_max_luns; */
704f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
7058dea0d02SFUJITA Tomonori 	}
7068dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
7078dea0d02SFUJITA Tomonori }
7088dea0d02SFUJITA Tomonori 
70922017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
71022017ed2SDouglas Gilbert 
71122017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
71222017ed2SDouglas Gilbert static void
71322017ed2SDouglas Gilbert mk_sense_invalid_fld(struct scsi_cmnd *scp, enum sdeb_cmd_data c_d,
71422017ed2SDouglas Gilbert 		     int in_byte, int in_bit)
71522017ed2SDouglas Gilbert {
71622017ed2SDouglas Gilbert 	unsigned char *sbuff;
71722017ed2SDouglas Gilbert 	u8 sks[4];
71822017ed2SDouglas Gilbert 	int sl, asc;
71922017ed2SDouglas Gilbert 
72022017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
72122017ed2SDouglas Gilbert 	if (!sbuff) {
72222017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
72322017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
72422017ed2SDouglas Gilbert 		return;
72522017ed2SDouglas Gilbert 	}
72622017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
72722017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
72822017ed2SDouglas Gilbert 	scsi_build_sense_buffer(scsi_debug_dsense, sbuff, ILLEGAL_REQUEST,
72922017ed2SDouglas Gilbert 				asc, 0);
73022017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
73122017ed2SDouglas Gilbert 	sks[0] = 0x80;
73222017ed2SDouglas Gilbert 	if (c_d)
73322017ed2SDouglas Gilbert 		sks[0] |= 0x40;
73422017ed2SDouglas Gilbert 	if (in_bit >= 0) {
73522017ed2SDouglas Gilbert 		sks[0] |= 0x8;
73622017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
73722017ed2SDouglas Gilbert 	}
73822017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
73922017ed2SDouglas Gilbert 	if (scsi_debug_dsense) {
74022017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
74122017ed2SDouglas Gilbert 		sbuff[7] = sl;
74222017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
74322017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
74422017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
74522017ed2SDouglas Gilbert 	} else
74622017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
74722017ed2SDouglas Gilbert 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
74822017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
74922017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
75022017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
75122017ed2SDouglas Gilbert }
75222017ed2SDouglas Gilbert 
753cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
7548dea0d02SFUJITA Tomonori {
7558dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
7568dea0d02SFUJITA Tomonori 
757cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
758cbf67842SDouglas Gilbert 	if (!sbuff) {
759cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
760cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
761cbf67842SDouglas Gilbert 		return;
762cbf67842SDouglas Gilbert 	}
763cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
7648dea0d02SFUJITA Tomonori 
7658dea0d02SFUJITA Tomonori 	scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
7668dea0d02SFUJITA Tomonori 
7678dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
768cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
769cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
770cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
7718dea0d02SFUJITA Tomonori }
7721da177e4SLinus Torvalds 
77322017ed2SDouglas Gilbert static void
77422017ed2SDouglas Gilbert mk_sense_invalid_opcode(struct scsi_cmnd *scp)
77522017ed2SDouglas Gilbert {
77622017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
77722017ed2SDouglas Gilbert }
77822017ed2SDouglas Gilbert 
7791da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
7801da177e4SLinus Torvalds {
7811da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
782cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
783cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
784cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
785cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
786cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
787cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
788cbf67842SDouglas Gilbert 				    __func__);
789cbf67842SDouglas Gilbert 		else
790cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
791cbf67842SDouglas Gilbert 				    __func__, cmd);
7921da177e4SLinus Torvalds 	}
7931da177e4SLinus Torvalds 	return -EINVAL;
7941da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
7951da177e4SLinus Torvalds }
7961da177e4SLinus Torvalds 
79719c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
79819c8ead7SEwan D. Milne {
79919c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
80019c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
80119c8ead7SEwan D. Milne 
80219c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
80319c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
80419c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
80519c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
80619c8ead7SEwan D. Milne 			    (devip->target == dp->target))
80719c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
80819c8ead7SEwan D. Milne 		}
80919c8ead7SEwan D. Milne 	}
81019c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
81119c8ead7SEwan D. Milne }
81219c8ead7SEwan D. Milne 
813cbf67842SDouglas Gilbert static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only,
814c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
8151da177e4SLinus Torvalds {
816cbf67842SDouglas Gilbert 	int k;
817cbf67842SDouglas Gilbert 	bool debug = !!(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts);
818cbf67842SDouglas Gilbert 
819cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
820cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
821cbf67842SDouglas Gilbert 		const char *cp = NULL;
822cbf67842SDouglas Gilbert 
823cbf67842SDouglas Gilbert 		switch (k) {
824cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
825cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
826cbf67842SDouglas Gilbert 					UA_RESET_ASC, POWER_ON_RESET_ASCQ);
827cbf67842SDouglas Gilbert 			if (debug)
828cbf67842SDouglas Gilbert 				cp = "power on reset";
829cbf67842SDouglas Gilbert 			break;
830cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
831cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
832cbf67842SDouglas Gilbert 					UA_RESET_ASC, BUS_RESET_ASCQ);
833cbf67842SDouglas Gilbert 			if (debug)
834cbf67842SDouglas Gilbert 				cp = "bus reset";
835cbf67842SDouglas Gilbert 			break;
836cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
837cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
838cbf67842SDouglas Gilbert 					UA_CHANGED_ASC, MODE_CHANGED_ASCQ);
839cbf67842SDouglas Gilbert 			if (debug)
840cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
841cbf67842SDouglas Gilbert 			break;
8420d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
8430d01c5dfSDouglas Gilbert 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
8440d01c5dfSDouglas Gilbert 					UA_CHANGED_ASC, CAPACITY_CHANGED_ASCQ);
8450d01c5dfSDouglas Gilbert 			if (debug)
8460d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
847f49accf1SEwan D. Milne 			break;
848acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
849acafd0b9SEwan D. Milne 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
850acafd0b9SEwan D. Milne 				 TARGET_CHANGED_ASC, MICROCODE_CHANGED_ASCQ);
851acafd0b9SEwan D. Milne 			if (debug)
852acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
853acafd0b9SEwan D. Milne 			break;
854acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
855acafd0b9SEwan D. Milne 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
856acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
857acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
858acafd0b9SEwan D. Milne 			if (debug)
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.
86719c8ead7SEwan D. Milne 			 * NOTE:  scsi_debug_scsi_level does not use the same
86819c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
86919c8ead7SEwan D. Milne 			 */
87019c8ead7SEwan D. Milne 			if (scsi_debug_scsi_level >= 6)	/* SPC-4 and above */
87119c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
87219c8ead7SEwan D. Milne 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
87319c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
87419c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
87519c8ead7SEwan D. Milne 			if (debug)
87619c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
87719c8ead7SEwan D. Milne 			break;
878cbf67842SDouglas Gilbert 		default:
879cbf67842SDouglas Gilbert 			pr_warn("%s: unexpected unit attention code=%d\n",
880cbf67842SDouglas Gilbert 				__func__, k);
881cbf67842SDouglas Gilbert 			if (debug)
882cbf67842SDouglas Gilbert 				cp = "unknown";
883cbf67842SDouglas Gilbert 			break;
884cbf67842SDouglas Gilbert 		}
885cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
886cbf67842SDouglas Gilbert 		if (debug)
887cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
888cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
889cbf67842SDouglas Gilbert 				   my_name, cp);
8901da177e4SLinus Torvalds 		return check_condition_result;
8911da177e4SLinus Torvalds 	}
892cbf67842SDouglas Gilbert 	if ((UAS_TUR == uas_only) && devip->stopped) {
893cbf67842SDouglas Gilbert 		mk_sense_buffer(SCpnt, NOT_READY, LOGICAL_UNIT_NOT_READY,
894c65b1445SDouglas Gilbert 				0x2);
895cbf67842SDouglas Gilbert 		if (debug)
896cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
897cbf67842SDouglas Gilbert 				    "%s reports: Not ready: %s\n", my_name,
898cbf67842SDouglas Gilbert 				    "initializing command required");
899c65b1445SDouglas Gilbert 		return check_condition_result;
900c65b1445SDouglas Gilbert 	}
9011da177e4SLinus Torvalds 	return 0;
9021da177e4SLinus Torvalds }
9031da177e4SLinus Torvalds 
9041da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
9051da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
9061da177e4SLinus Torvalds 				int arr_len)
9071da177e4SLinus Torvalds {
90821a61829SFUJITA Tomonori 	int act_len;
909072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
9101da177e4SLinus Torvalds 
911072d0bb3SFUJITA Tomonori 	if (!sdb->length)
9121da177e4SLinus Torvalds 		return 0;
913072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
9141da177e4SLinus Torvalds 		return (DID_ERROR << 16);
91521a61829SFUJITA Tomonori 
91621a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
91721a61829SFUJITA Tomonori 				      arr, arr_len);
91821a61829SFUJITA Tomonori 	sdb->resid = scsi_bufflen(scp) - act_len;
91921a61829SFUJITA Tomonori 
9201da177e4SLinus Torvalds 	return 0;
9211da177e4SLinus Torvalds }
9221da177e4SLinus Torvalds 
9231da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */
9241da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
92521a61829SFUJITA Tomonori 			       int arr_len)
9261da177e4SLinus Torvalds {
92721a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
9281da177e4SLinus Torvalds 		return 0;
929072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
9301da177e4SLinus Torvalds 		return -1;
93121a61829SFUJITA Tomonori 
93221a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
9331da177e4SLinus Torvalds }
9341da177e4SLinus Torvalds 
9351da177e4SLinus Torvalds 
9361da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux   ";
9371da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug      ";
938cbf67842SDouglas Gilbert static const char *inq_product_rev = "0184";	/* version less '.' */
9391da177e4SLinus Torvalds 
940cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
9415a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
9425a09e398SHannes Reinecke 			   int target_dev_id, int dev_id_num,
9435a09e398SHannes Reinecke 			   const char * dev_id_str,
944c65b1445SDouglas Gilbert 			   int dev_id_str_len)
9451da177e4SLinus Torvalds {
946c65b1445SDouglas Gilbert 	int num, port_a;
947c65b1445SDouglas Gilbert 	char b[32];
9481da177e4SLinus Torvalds 
949c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
9501da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
9511da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
9521da177e4SLinus Torvalds 	arr[1] = 0x1;
9531da177e4SLinus Torvalds 	arr[2] = 0x0;
9541da177e4SLinus Torvalds 	memcpy(&arr[4], inq_vendor_id, 8);
9551da177e4SLinus Torvalds 	memcpy(&arr[12], inq_product_id, 16);
9561da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
9571da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
9581da177e4SLinus Torvalds 	arr[3] = num;
9591da177e4SLinus Torvalds 	num += 4;
960c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
961c65b1445SDouglas Gilbert 		/* NAA-5, Logical unit identifier (binary) */
962c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* binary (not necessarily sas) */
963c65b1445SDouglas Gilbert 		arr[num++] = 0x3;	/* PIV=0, lu, naa */
964c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
965c65b1445SDouglas Gilbert 		arr[num++] = 0x8;
966c65b1445SDouglas Gilbert 		arr[num++] = 0x53;  /* naa-5 ieee company id=0x333333 (fake) */
967c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
968c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
969c65b1445SDouglas Gilbert 		arr[num++] = 0x30;
970c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 24);
971c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 16) & 0xff;
972c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 8) & 0xff;
973c65b1445SDouglas Gilbert 		arr[num++] = dev_id_num & 0xff;
974c65b1445SDouglas Gilbert 		/* Target relative port number */
975c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
976c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
977c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
978c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
979c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
980c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
981c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
982c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
983c65b1445SDouglas Gilbert 	}
984c65b1445SDouglas Gilbert 	/* NAA-5, Target port identifier */
985c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
986c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
987c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
988c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
989c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
990c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
991c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
992c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
993c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
994c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
995c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
996c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
9975a09e398SHannes Reinecke 	/* NAA-5, Target port group identifier */
9985a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
9995a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
10005a09e398SHannes Reinecke 	arr[num++] = 0x0;
10015a09e398SHannes Reinecke 	arr[num++] = 0x4;
10025a09e398SHannes Reinecke 	arr[num++] = 0;
10035a09e398SHannes Reinecke 	arr[num++] = 0;
10045a09e398SHannes Reinecke 	arr[num++] = (port_group_id >> 8) & 0xff;
10055a09e398SHannes Reinecke 	arr[num++] = port_group_id & 0xff;
1006c65b1445SDouglas Gilbert 	/* NAA-5, Target device identifier */
1007c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1008c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
1009c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1010c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
1011c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
1012c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
1013c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
1014c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
1015c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 24);
1016c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 16) & 0xff;
1017c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 8) & 0xff;
1018c65b1445SDouglas Gilbert 	arr[num++] = target_dev_id & 0xff;
1019c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1020c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1021c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1022c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1023c65b1445SDouglas Gilbert 	arr[num++] = 24;
1024c65b1445SDouglas Gilbert 	memcpy(arr + num, "naa.52222220", 12);
1025c65b1445SDouglas Gilbert 	num += 12;
1026c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1027c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1028c65b1445SDouglas Gilbert 	num += 8;
1029c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1030c65b1445SDouglas Gilbert 	num += 4;
1031c65b1445SDouglas Gilbert 	return num;
1032c65b1445SDouglas Gilbert }
1033c65b1445SDouglas Gilbert 
1034c65b1445SDouglas Gilbert 
1035c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1036c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1037c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1038c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1039c65b1445SDouglas Gilbert };
1040c65b1445SDouglas Gilbert 
1041cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1042c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr)
1043c65b1445SDouglas Gilbert {
1044c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1045c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1046c65b1445SDouglas Gilbert }
1047c65b1445SDouglas Gilbert 
1048cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1049c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr)
1050c65b1445SDouglas Gilbert {
1051c65b1445SDouglas Gilbert 	int num = 0;
1052c65b1445SDouglas Gilbert 	const char * na1 = "https://www.kernel.org/config";
1053c65b1445SDouglas Gilbert 	const char * na2 = "http://www.kernel.org/log";
1054c65b1445SDouglas Gilbert 	int plen, olen;
1055c65b1445SDouglas Gilbert 
1056c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1057c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1058c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1059c65b1445SDouglas Gilbert 	olen = strlen(na1);
1060c65b1445SDouglas Gilbert 	plen = olen + 1;
1061c65b1445SDouglas Gilbert 	if (plen % 4)
1062c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1063c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1064c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1065c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1066c65b1445SDouglas Gilbert 	num += plen;
1067c65b1445SDouglas Gilbert 
1068c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1069c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1070c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1071c65b1445SDouglas Gilbert 	olen = strlen(na2);
1072c65b1445SDouglas Gilbert 	plen = olen + 1;
1073c65b1445SDouglas Gilbert 	if (plen % 4)
1074c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1075c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1076c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1077c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1078c65b1445SDouglas Gilbert 	num += plen;
1079c65b1445SDouglas Gilbert 
1080c65b1445SDouglas Gilbert 	return num;
1081c65b1445SDouglas Gilbert }
1082c65b1445SDouglas Gilbert 
1083c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1084c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
1085c65b1445SDouglas Gilbert {
1086c65b1445SDouglas Gilbert 	int num = 0;
1087c65b1445SDouglas Gilbert 	int port_a, port_b;
1088c65b1445SDouglas Gilbert 
1089c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1090c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1091c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1092c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1093c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1094c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1095c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1096c65b1445SDouglas Gilbert 	num += 6;
1097c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1098c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1099c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1100c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1101c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1102c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1103c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
1104c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
1105c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
1106c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
1107c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
1108c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
1109c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
1110c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
1111c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
1112c65b1445SDouglas Gilbert 
1113c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1114c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1115c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1116c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1117c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1118c65b1445SDouglas Gilbert 	num += 6;
1119c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1120c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1121c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1122c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1123c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1124c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1125c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
1126c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
1127c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
1128c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
1129c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
1130c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 24);
1131c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 16) & 0xff;
1132c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 8) & 0xff;
1133c65b1445SDouglas Gilbert 	arr[num++] = port_b & 0xff;
1134c65b1445SDouglas Gilbert 
1135c65b1445SDouglas Gilbert 	return num;
1136c65b1445SDouglas Gilbert }
1137c65b1445SDouglas Gilbert 
1138c65b1445SDouglas Gilbert 
1139c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1140c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1141c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1142c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1143c65b1445SDouglas Gilbert '1','2','3','4',
1144c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1145c65b1445SDouglas Gilbert 0xec,0,0,0,
1146c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1147c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1148c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1149c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1150c65b1445SDouglas Gilbert 0x53,0x41,
1151c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1152c65b1445SDouglas Gilbert 0x20,0x20,
1153c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1154c65b1445SDouglas Gilbert 0x10,0x80,
1155c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1156c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1157c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1158c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1159c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1160c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1161c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1162c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1163c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1164c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1165c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1166c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1167c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1168c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1169c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1170c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0xa5,0x51,
1181c65b1445SDouglas Gilbert };
1182c65b1445SDouglas Gilbert 
1183cbf67842SDouglas Gilbert /* ATA Information VPD page */
1184c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr)
1185c65b1445SDouglas Gilbert {
1186c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1187c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1188c65b1445SDouglas Gilbert }
1189c65b1445SDouglas Gilbert 
1190c65b1445SDouglas Gilbert 
1191c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
11921e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
11931e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11941e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11951e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1196c65b1445SDouglas Gilbert };
1197c65b1445SDouglas Gilbert 
1198cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1199c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr)
1200c65b1445SDouglas Gilbert {
1201ea61fca5SMartin K. Petersen 	unsigned int gran;
1202ea61fca5SMartin K. Petersen 
1203c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1204e308b3d1SMartin K. Petersen 
1205e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
1206ea61fca5SMartin K. Petersen 	gran = 1 << scsi_debug_physblk_exp;
1207ea61fca5SMartin K. Petersen 	arr[2] = (gran >> 8) & 0xff;
1208ea61fca5SMartin K. Petersen 	arr[3] = gran & 0xff;
1209e308b3d1SMartin K. Petersen 
1210e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1211c65b1445SDouglas Gilbert 	if (sdebug_store_sectors > 0x400) {
1212c65b1445SDouglas Gilbert 		arr[4] = (sdebug_store_sectors >> 24) & 0xff;
1213c65b1445SDouglas Gilbert 		arr[5] = (sdebug_store_sectors >> 16) & 0xff;
1214c65b1445SDouglas Gilbert 		arr[6] = (sdebug_store_sectors >> 8) & 0xff;
1215c65b1445SDouglas Gilbert 		arr[7] = sdebug_store_sectors & 0xff;
1216c65b1445SDouglas Gilbert 	}
121744d92694SMartin K. Petersen 
1218e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1219e308b3d1SMartin K. Petersen 	put_unaligned_be32(scsi_debug_opt_blks, &arr[8]);
1220e308b3d1SMartin K. Petersen 
12215b94e232SMartin K. Petersen 	if (scsi_debug_lbpu) {
1222e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
12236014759cSMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]);
1224e308b3d1SMartin K. Petersen 
1225e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
122644d92694SMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
122744d92694SMartin K. Petersen 	}
122844d92694SMartin K. Petersen 
1229e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
123044d92694SMartin K. Petersen 	if (scsi_debug_unmap_alignment) {
123144d92694SMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
123244d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
123344d92694SMartin K. Petersen 	}
123444d92694SMartin K. Petersen 
1235e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
123644d92694SMartin K. Petersen 	put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
12376014759cSMartin K. Petersen 
12385b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
12395b94e232SMartin K. Petersen 	put_unaligned_be64(scsi_debug_write_same_length, &arr[32]);
12405b94e232SMartin K. Petersen 
12415b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
124244d92694SMartin K. Petersen 
1243c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
12441da177e4SLinus Torvalds }
12451da177e4SLinus Torvalds 
12461e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
1247eac6e8e4SMatthew Wilcox static int inquiry_evpd_b1(unsigned char *arr)
1248eac6e8e4SMatthew Wilcox {
1249eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1250eac6e8e4SMatthew Wilcox 	arr[0] = 0;
12511e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
12521e49f785SDouglas Gilbert 	arr[2] = 0;
12531e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
1254eac6e8e4SMatthew Wilcox 
1255eac6e8e4SMatthew Wilcox 	return 0x3c;
1256eac6e8e4SMatthew Wilcox }
12571da177e4SLinus Torvalds 
1258be1dd78dSEric Sandeen /* Logical block provisioning VPD page (SBC-3) */
12596014759cSMartin K. Petersen static int inquiry_evpd_b2(unsigned char *arr)
12606014759cSMartin K. Petersen {
12613f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
12626014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
12636014759cSMartin K. Petersen 
12645b94e232SMartin K. Petersen 	if (scsi_debug_lbpu)
12656014759cSMartin K. Petersen 		arr[1] = 1 << 7;
12666014759cSMartin K. Petersen 
12675b94e232SMartin K. Petersen 	if (scsi_debug_lbpws)
12686014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
12696014759cSMartin K. Petersen 
12705b94e232SMartin K. Petersen 	if (scsi_debug_lbpws10)
12715b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
12725b94e232SMartin K. Petersen 
1273be1dd78dSEric Sandeen 	if (scsi_debug_lbprz)
1274be1dd78dSEric Sandeen 		arr[1] |= 1 << 2;
1275be1dd78dSEric Sandeen 
12763f0bc3b3SMartin K. Petersen 	return 0x4;
12776014759cSMartin K. Petersen }
12786014759cSMartin K. Petersen 
12791da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1280c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
12811da177e4SLinus Torvalds 
1282c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
12831da177e4SLinus Torvalds {
12841da177e4SLinus Torvalds 	unsigned char pq_pdt;
12855a09e398SHannes Reinecke 	unsigned char * arr;
128601123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
12875a09e398SHannes Reinecke 	int alloc_len, n, ret;
1288c2248fc9SDouglas Gilbert 	bool have_wlun;
12891da177e4SLinus Torvalds 
12901da177e4SLinus Torvalds 	alloc_len = (cmd[3] << 8) + cmd[4];
12916f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
12926f3cbf55SDouglas Gilbert 	if (! arr)
12936f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
129434d55434STomas Winkler 	have_wlun = (scp->device->lun == SCSI_W_LUN_REPORT_LUNS);
1295c2248fc9SDouglas Gilbert 	if (have_wlun)
1296c65b1445SDouglas Gilbert 		pq_pdt = 0x1e;	/* present, wlun */
1297c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (0 == devip->lun))
1298c65b1445SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, no device type */
1299c65b1445SDouglas Gilbert 	else
13001da177e4SLinus Torvalds 		pq_pdt = (scsi_debug_ptype & 0x1f);
13011da177e4SLinus Torvalds 	arr[0] = pq_pdt;
13021da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
130322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
13045a09e398SHannes Reinecke 		kfree(arr);
13051da177e4SLinus Torvalds 		return check_condition_result;
13061da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
13075a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1308c65b1445SDouglas Gilbert 		char lu_id_str[6];
1309c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
13101da177e4SLinus Torvalds 
13115a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
13125a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
131323183910SDouglas Gilbert 		if (0 == scsi_debug_vpd_use_hostno)
131423183910SDouglas Gilbert 			host_no = 0;
1315c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1316c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1317c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1318c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1319c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
13201da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1321c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1322c65b1445SDouglas Gilbert 			n = 4;
1323c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1324c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1325c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1326c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1327c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1328c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1329c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1330c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1331c65b1445SDouglas Gilbert 			arr[n++] = 0x89;  /* ATA information */
1332c65b1445SDouglas Gilbert 			arr[n++] = 0xb0;  /* Block limits (SBC) */
1333eac6e8e4SMatthew Wilcox 			arr[n++] = 0xb1;  /* Block characteristics (SBC) */
13345b94e232SMartin K. Petersen 			if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
13355b94e232SMartin K. Petersen 				arr[n++] = 0xb2;
1336c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
13371da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1338c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
13391da177e4SLinus Torvalds 			arr[3] = len;
1340c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
13411da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1342c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
13435a09e398SHannes Reinecke 			arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
13445a09e398SHannes Reinecke 						 target_dev_id, lu_id_num,
13455a09e398SHannes Reinecke 						 lu_id_str, len);
1346c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1347c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1348c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_84(&arr[4]);
1349c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1350c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1351c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_85(&arr[4]);
1352c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1353c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1354c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
1355c6a44287SMartin K. Petersen 			if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
1356c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1357c6a44287SMartin K. Petersen 			else if (scsi_debug_dif)
1358c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1359c6a44287SMartin K. Petersen 			else
1360c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1361c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1362c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1363c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1364c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1365c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1366c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1367c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1368c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1369c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1370c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1371c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1372c65b1445SDouglas Gilbert 		} else if (0x89 == cmd[2]) { /* ATA information */
1373c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1374c65b1445SDouglas Gilbert 			n = inquiry_evpd_89(&arr[4]);
1375c65b1445SDouglas Gilbert 			arr[2] = (n >> 8);
1376c65b1445SDouglas Gilbert 			arr[3] = (n & 0xff);
1377c65b1445SDouglas Gilbert 		} else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1378c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1379c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_b0(&arr[4]);
1380eac6e8e4SMatthew Wilcox 		} else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
1381eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
1382eac6e8e4SMatthew Wilcox 			arr[3] = inquiry_evpd_b1(&arr[4]);
13835b94e232SMartin K. Petersen 		} else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
13846014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
13856014759cSMartin K. Petersen 			arr[3] = inquiry_evpd_b2(&arr[4]);
13861da177e4SLinus Torvalds 		} else {
138722017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
13885a09e398SHannes Reinecke 			kfree(arr);
13891da177e4SLinus Torvalds 			return check_condition_result;
13901da177e4SLinus Torvalds 		}
1391c65b1445SDouglas Gilbert 		len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
13925a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1393c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
13945a09e398SHannes Reinecke 		kfree(arr);
13955a09e398SHannes Reinecke 		return ret;
13961da177e4SLinus Torvalds 	}
13971da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1398d986788bSMartin Pitt 	arr[1] = scsi_debug_removable ? 0x80 : 0;	/* Removable disk */
13991da177e4SLinus Torvalds 	arr[2] = scsi_debug_scsi_level;
14001da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
14011da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1402c6a44287SMartin K. Petersen 	arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
14035a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno)
14045a09e398SHannes Reinecke 		arr[5] = 0x10; /* claim: implicit TGPS */
1405c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
14061da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1407c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
14081da177e4SLinus Torvalds 	memcpy(&arr[8], inq_vendor_id, 8);
14091da177e4SLinus Torvalds 	memcpy(&arr[16], inq_product_id, 16);
14101da177e4SLinus Torvalds 	memcpy(&arr[32], inq_product_rev, 4);
14111da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1412e46b0344SDouglas Gilbert 	arr[58] = 0x0; arr[59] = 0xa2;  /* SAM-5 rev 4 */
1413e46b0344SDouglas Gilbert 	arr[60] = 0x4; arr[61] = 0x68;  /* SPC-4 rev 37 */
1414c65b1445SDouglas Gilbert 	n = 62;
14151da177e4SLinus Torvalds 	if (scsi_debug_ptype == 0) {
1416e46b0344SDouglas Gilbert 		arr[n++] = 0x4; arr[n++] = 0xc5; /* SBC-4 rev 36 */
14171da177e4SLinus Torvalds 	} else if (scsi_debug_ptype == 1) {
1418e46b0344SDouglas Gilbert 		arr[n++] = 0x5; arr[n++] = 0x25; /* SSC-4 rev 3 */
14191da177e4SLinus Torvalds 	}
1420e46b0344SDouglas Gilbert 	arr[n++] = 0x20; arr[n++] = 0xe6;  /* SPL-3 rev 7 */
14215a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
14221da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
14235a09e398SHannes Reinecke 	kfree(arr);
14245a09e398SHannes Reinecke 	return ret;
14251da177e4SLinus Torvalds }
14261da177e4SLinus Torvalds 
14271da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp,
14281da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip)
14291da177e4SLinus Torvalds {
14301da177e4SLinus Torvalds 	unsigned char * sbuff;
143101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1432cbf67842SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
14332492fc09STomas Winkler 	bool dsense;
14341da177e4SLinus Torvalds 	int len = 18;
14351da177e4SLinus Torvalds 
1436c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1437c2248fc9SDouglas Gilbert 	dsense = !!(cmd[1] & 1);
1438cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
1439c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1440c2248fc9SDouglas Gilbert 		if (dsense) {
1441c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1442c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1443c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
1444c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
1445c2248fc9SDouglas Gilbert 			len = 8;
1446c65b1445SDouglas Gilbert 		} else {
1447c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1448c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1449c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1450c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
1451c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
1452c65b1445SDouglas Gilbert 		}
1453c65b1445SDouglas Gilbert 	} else {
1454cbf67842SDouglas Gilbert 		memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
1455c2248fc9SDouglas Gilbert 		if (arr[0] >= 0x70 && dsense == scsi_debug_dsense)
1456c2248fc9SDouglas Gilbert 			;	/* have sense and formats match */
1457c2248fc9SDouglas Gilbert 		else if (arr[0] <= 0x70) {
1458c2248fc9SDouglas Gilbert 			if (dsense) {
1459c2248fc9SDouglas Gilbert 				memset(arr, 0, 8);
1460c2248fc9SDouglas Gilbert 				arr[0] = 0x72;
1461c2248fc9SDouglas Gilbert 				len = 8;
1462c2248fc9SDouglas Gilbert 			} else {
1463c2248fc9SDouglas Gilbert 				memset(arr, 0, 18);
1464c2248fc9SDouglas Gilbert 				arr[0] = 0x70;
1465c2248fc9SDouglas Gilbert 				arr[7] = 0xa;
1466c2248fc9SDouglas Gilbert 			}
1467c2248fc9SDouglas Gilbert 		} else if (dsense) {
1468c2248fc9SDouglas Gilbert 			memset(arr, 0, 8);
14691da177e4SLinus Torvalds 			arr[0] = 0x72;
14701da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
14711da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
14721da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
14731da177e4SLinus Torvalds 			len = 8;
1474c2248fc9SDouglas Gilbert 		} else {
1475c2248fc9SDouglas Gilbert 			memset(arr, 0, 18);
1476c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1477c2248fc9SDouglas Gilbert 			arr[2] = sbuff[1];
1478c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1479c2248fc9SDouglas Gilbert 			arr[12] = sbuff[1];
1480c2248fc9SDouglas Gilbert 			arr[13] = sbuff[3];
1481c65b1445SDouglas Gilbert 		}
1482c2248fc9SDouglas Gilbert 
1483c65b1445SDouglas Gilbert 	}
1484cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
14851da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
14861da177e4SLinus Torvalds }
14871da177e4SLinus Torvalds 
1488c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp,
1489c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
1490c65b1445SDouglas Gilbert {
149101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1492c2248fc9SDouglas Gilbert 	int power_cond, start;
1493c65b1445SDouglas Gilbert 
1494c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1495c65b1445SDouglas Gilbert 	if (power_cond) {
149622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1497c65b1445SDouglas Gilbert 		return check_condition_result;
1498c65b1445SDouglas Gilbert 	}
1499c65b1445SDouglas Gilbert 	start = cmd[4] & 1;
1500c65b1445SDouglas Gilbert 	if (start == devip->stopped)
1501c65b1445SDouglas Gilbert 		devip->stopped = !start;
1502c65b1445SDouglas Gilbert 	return 0;
1503c65b1445SDouglas Gilbert }
1504c65b1445SDouglas Gilbert 
150528898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
150628898873SFUJITA Tomonori {
150728898873SFUJITA Tomonori 	if (scsi_debug_virtual_gb > 0)
15085447ed6cSDouglas Gilbert 		return (sector_t)scsi_debug_virtual_gb *
15095447ed6cSDouglas Gilbert 			(1073741824 / scsi_debug_sector_size);
151028898873SFUJITA Tomonori 	else
151128898873SFUJITA Tomonori 		return sdebug_store_sectors;
151228898873SFUJITA Tomonori }
151328898873SFUJITA Tomonori 
15141da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
15151da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp,
15161da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
15171da177e4SLinus Torvalds {
15181da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1519c65b1445SDouglas Gilbert 	unsigned int capac;
15201da177e4SLinus Torvalds 
1521c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
152228898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
15231da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1524c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1525c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
15261da177e4SLinus Torvalds 		arr[0] = (capac >> 24);
15271da177e4SLinus Torvalds 		arr[1] = (capac >> 16) & 0xff;
15281da177e4SLinus Torvalds 		arr[2] = (capac >> 8) & 0xff;
15291da177e4SLinus Torvalds 		arr[3] = capac & 0xff;
1530c65b1445SDouglas Gilbert 	} else {
1531c65b1445SDouglas Gilbert 		arr[0] = 0xff;
1532c65b1445SDouglas Gilbert 		arr[1] = 0xff;
1533c65b1445SDouglas Gilbert 		arr[2] = 0xff;
1534c65b1445SDouglas Gilbert 		arr[3] = 0xff;
1535c65b1445SDouglas Gilbert 	}
1536597136abSMartin K. Petersen 	arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
1537597136abSMartin K. Petersen 	arr[7] = scsi_debug_sector_size & 0xff;
15381da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
15391da177e4SLinus Torvalds }
15401da177e4SLinus Torvalds 
1541c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1542c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp,
1543c65b1445SDouglas Gilbert 			  struct sdebug_dev_info * devip)
1544c65b1445SDouglas Gilbert {
154501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1546c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1547c65b1445SDouglas Gilbert 	unsigned long long capac;
1548c2248fc9SDouglas Gilbert 	int k, alloc_len;
1549c65b1445SDouglas Gilbert 
1550c65b1445SDouglas Gilbert 	alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1551c65b1445SDouglas Gilbert 		     + cmd[13]);
1552c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
155328898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1554c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1555c65b1445SDouglas Gilbert 	capac = sdebug_capacity - 1;
1556c65b1445SDouglas Gilbert 	for (k = 0; k < 8; ++k, capac >>= 8)
1557c65b1445SDouglas Gilbert 		arr[7 - k] = capac & 0xff;
1558597136abSMartin K. Petersen 	arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
1559597136abSMartin K. Petersen 	arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
1560597136abSMartin K. Petersen 	arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
1561597136abSMartin K. Petersen 	arr[11] = scsi_debug_sector_size & 0xff;
1562ea61fca5SMartin K. Petersen 	arr[13] = scsi_debug_physblk_exp & 0xf;
1563ea61fca5SMartin K. Petersen 	arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
156444d92694SMartin K. Petersen 
1565be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
15665b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1567be1dd78dSEric Sandeen 		if (scsi_debug_lbprz)
1568be1dd78dSEric Sandeen 			arr[14] |= 0x40; /* LBPRZ */
1569be1dd78dSEric Sandeen 	}
157044d92694SMartin K. Petersen 
1571ea61fca5SMartin K. Petersen 	arr[15] = scsi_debug_lowest_aligned & 0xff;
1572c6a44287SMartin K. Petersen 
1573c6a44287SMartin K. Petersen 	if (scsi_debug_dif) {
1574c6a44287SMartin K. Petersen 		arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
1575c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1576c6a44287SMartin K. Petersen 	}
1577c6a44287SMartin K. Petersen 
1578c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1579c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1580c65b1445SDouglas Gilbert }
1581c65b1445SDouglas Gilbert 
15825a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
15835a09e398SHannes Reinecke 
15845a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp,
15855a09e398SHannes Reinecke 			      struct sdebug_dev_info * devip)
15865a09e398SHannes Reinecke {
158701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
15885a09e398SHannes Reinecke 	unsigned char * arr;
15895a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
15905a09e398SHannes Reinecke 	int n, ret, alen, rlen;
15915a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
15925a09e398SHannes Reinecke 
15935a09e398SHannes Reinecke 	alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
15945a09e398SHannes Reinecke 		+ cmd[9]);
15955a09e398SHannes Reinecke 
15966f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
15976f3cbf55SDouglas Gilbert 	if (! arr)
15986f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
15995a09e398SHannes Reinecke 	/*
16005a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
16015a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
16025a09e398SHannes Reinecke 	 * So we create two port groups with one port each
16035a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
16045a09e398SHannes Reinecke 	 */
16055a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
16065a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
16075a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
16085a09e398SHannes Reinecke 	    (devip->channel & 0x7f);
16095a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
16105a09e398SHannes Reinecke 	    (devip->channel & 0x7f) + 0x80;
16115a09e398SHannes Reinecke 
16125a09e398SHannes Reinecke 	/*
16135a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
16145a09e398SHannes Reinecke 	 */
16155a09e398SHannes Reinecke 	n = 4;
16165a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno) {
16175a09e398SHannes Reinecke 	    arr[n++] = host_no % 3; /* Asymm access state */
16185a09e398SHannes Reinecke 	    arr[n++] = 0x0F; /* claim: all states are supported */
16195a09e398SHannes Reinecke 	} else {
16205a09e398SHannes Reinecke 	    arr[n++] = 0x0; /* Active/Optimized path */
16215a09e398SHannes Reinecke 	    arr[n++] = 0x01; /* claim: only support active/optimized paths */
16225a09e398SHannes Reinecke 	}
16235a09e398SHannes Reinecke 	arr[n++] = (port_group_a >> 8) & 0xff;
16245a09e398SHannes Reinecke 	arr[n++] = port_group_a & 0xff;
16255a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
16265a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
16275a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
16285a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
16295a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
16305a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
16315a09e398SHannes Reinecke 	arr[n++] = (port_a >> 8) & 0xff;
16325a09e398SHannes Reinecke 	arr[n++] = port_a & 0xff;
16335a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
16345a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
16355a09e398SHannes Reinecke 	arr[n++] = (port_group_b >> 8) & 0xff;
16365a09e398SHannes Reinecke 	arr[n++] = port_group_b & 0xff;
16375a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
16385a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
16395a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
16405a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
16415a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
16425a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
16435a09e398SHannes Reinecke 	arr[n++] = (port_b >> 8) & 0xff;
16445a09e398SHannes Reinecke 	arr[n++] = port_b & 0xff;
16455a09e398SHannes Reinecke 
16465a09e398SHannes Reinecke 	rlen = n - 4;
16475a09e398SHannes Reinecke 	arr[0] = (rlen >> 24) & 0xff;
16485a09e398SHannes Reinecke 	arr[1] = (rlen >> 16) & 0xff;
16495a09e398SHannes Reinecke 	arr[2] = (rlen >> 8) & 0xff;
16505a09e398SHannes Reinecke 	arr[3] = rlen & 0xff;
16515a09e398SHannes Reinecke 
16525a09e398SHannes Reinecke 	/*
16535a09e398SHannes Reinecke 	 * Return the smallest value of either
16545a09e398SHannes Reinecke 	 * - The allocated length
16555a09e398SHannes Reinecke 	 * - The constructed command length
16565a09e398SHannes Reinecke 	 * - The maximum array size
16575a09e398SHannes Reinecke 	 */
16585a09e398SHannes Reinecke 	rlen = min(alen,n);
16595a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
16605a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
16615a09e398SHannes Reinecke 	kfree(arr);
16625a09e398SHannes Reinecke 	return ret;
16635a09e398SHannes Reinecke }
16645a09e398SHannes Reinecke 
166538d5c833SDouglas Gilbert static int
166638d5c833SDouglas Gilbert resp_rsup_opcodes(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
166738d5c833SDouglas Gilbert {
166838d5c833SDouglas Gilbert 	bool rctd;
166938d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
167038d5c833SDouglas Gilbert 	u16 req_sa, u;
167138d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
167238d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
167338d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
167438d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
167538d5c833SDouglas Gilbert 	u8 *arr;
167638d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
167738d5c833SDouglas Gilbert 
167838d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
167938d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
168038d5c833SDouglas Gilbert 	req_opcode = cmd[3];
168138d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
168238d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
16836d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
168438d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
168538d5c833SDouglas Gilbert 		return check_condition_result;
168638d5c833SDouglas Gilbert 	}
168738d5c833SDouglas Gilbert 	if (alloc_len > 8192)
168838d5c833SDouglas Gilbert 		a_len = 8192;
168938d5c833SDouglas Gilbert 	else
169038d5c833SDouglas Gilbert 		a_len = alloc_len;
169199531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
169238d5c833SDouglas Gilbert 	if (NULL == arr) {
169338d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
169438d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
169538d5c833SDouglas Gilbert 		return check_condition_result;
169638d5c833SDouglas Gilbert 	}
169738d5c833SDouglas Gilbert 	switch (reporting_opts) {
169838d5c833SDouglas Gilbert 	case 0:	/* all commands */
169938d5c833SDouglas Gilbert 		/* count number of commands */
170038d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
170138d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
170238d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
170338d5c833SDouglas Gilbert 				continue;
170438d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
170538d5c833SDouglas Gilbert 		}
170638d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
170738d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
170838d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
170938d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
171038d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
171138d5c833SDouglas Gilbert 				continue;
171238d5c833SDouglas Gilbert 			na = oip->num_attached;
171338d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
171438d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
171538d5c833SDouglas Gilbert 			if (rctd)
171638d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
171738d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
171838d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
171938d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
172038d5c833SDouglas Gilbert 			if (rctd)
172138d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
172238d5c833SDouglas Gilbert 			r_oip = oip;
172338d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
172438d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
172538d5c833SDouglas Gilbert 					continue;
172638d5c833SDouglas Gilbert 				offset += bump;
172738d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
172838d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
172938d5c833SDouglas Gilbert 				if (rctd)
173038d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
173138d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
173238d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
173338d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
173438d5c833SDouglas Gilbert 						   arr + offset + 6);
173538d5c833SDouglas Gilbert 				if (rctd)
173638d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
173738d5c833SDouglas Gilbert 							   arr + offset + 8);
173838d5c833SDouglas Gilbert 			}
173938d5c833SDouglas Gilbert 			oip = r_oip;
174038d5c833SDouglas Gilbert 			offset += bump;
174138d5c833SDouglas Gilbert 		}
174238d5c833SDouglas Gilbert 		break;
174338d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
174438d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
174538d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
174638d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
174738d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
174838d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
174938d5c833SDouglas Gilbert 			supp = 1;
175038d5c833SDouglas Gilbert 			offset = 4;
175138d5c833SDouglas Gilbert 		} else {
175238d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
175338d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
175438d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
175538d5c833SDouglas Gilbert 							     2, 2);
175638d5c833SDouglas Gilbert 					kfree(arr);
175738d5c833SDouglas Gilbert 					return check_condition_result;
175838d5c833SDouglas Gilbert 				}
175938d5c833SDouglas Gilbert 				req_sa = 0;
176038d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
176138d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
176238d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
176338d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
176438d5c833SDouglas Gilbert 				return check_condition_result;
176538d5c833SDouglas Gilbert 			}
176638d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
176738d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
176838d5c833SDouglas Gilbert 				supp = 3;
176938d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
177038d5c833SDouglas Gilbert 				na = oip->num_attached;
177138d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
177238d5c833SDouglas Gilbert 				     ++k, ++oip) {
177338d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
177438d5c833SDouglas Gilbert 						break;
177538d5c833SDouglas Gilbert 				}
177638d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
177738d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
177838d5c833SDouglas Gilbert 				na = oip->num_attached;
177938d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
178038d5c833SDouglas Gilbert 				     ++k, ++oip) {
178138d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
178238d5c833SDouglas Gilbert 						break;
178338d5c833SDouglas Gilbert 				}
178438d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
178538d5c833SDouglas Gilbert 			} else
178638d5c833SDouglas Gilbert 				supp = 3;
178738d5c833SDouglas Gilbert 			if (3 == supp) {
178838d5c833SDouglas Gilbert 				u = oip->len_mask[0];
178938d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
179038d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
179138d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
179238d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
179338d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
179438d5c833SDouglas Gilbert 				offset = 4 + u;
179538d5c833SDouglas Gilbert 			} else
179638d5c833SDouglas Gilbert 				offset = 4;
179738d5c833SDouglas Gilbert 		}
179838d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
179938d5c833SDouglas Gilbert 		if (rctd) {
180038d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
180138d5c833SDouglas Gilbert 			offset += 12;
180238d5c833SDouglas Gilbert 		}
180338d5c833SDouglas Gilbert 		break;
180438d5c833SDouglas Gilbert 	default:
180538d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
180638d5c833SDouglas Gilbert 		kfree(arr);
180738d5c833SDouglas Gilbert 		return check_condition_result;
180838d5c833SDouglas Gilbert 	}
180938d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
181038d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
181138d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
181238d5c833SDouglas Gilbert 	kfree(arr);
181338d5c833SDouglas Gilbert 	return errsts;
181438d5c833SDouglas Gilbert }
181538d5c833SDouglas Gilbert 
181638d5c833SDouglas Gilbert static int
181738d5c833SDouglas Gilbert resp_rsup_tmfs(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
181838d5c833SDouglas Gilbert {
181938d5c833SDouglas Gilbert 	bool repd;
182038d5c833SDouglas Gilbert 	u32 alloc_len, len;
182138d5c833SDouglas Gilbert 	u8 arr[16];
182238d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
182338d5c833SDouglas Gilbert 
182438d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
182538d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
182638d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
182738d5c833SDouglas Gilbert 	if (alloc_len < 4) {
182838d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
182938d5c833SDouglas Gilbert 		return check_condition_result;
183038d5c833SDouglas Gilbert 	}
183138d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
183238d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
183338d5c833SDouglas Gilbert 	if (repd) {
183438d5c833SDouglas Gilbert 		arr[3] = 0xc;
183538d5c833SDouglas Gilbert 		len = 16;
183638d5c833SDouglas Gilbert 	} else
183738d5c833SDouglas Gilbert 		len = 4;
183838d5c833SDouglas Gilbert 
183938d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
184038d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
184138d5c833SDouglas Gilbert }
184238d5c833SDouglas Gilbert 
18431da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
18441da177e4SLinus Torvalds 
18451da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
18461da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
18471da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
18481da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
18491da177e4SLinus Torvalds 
18501da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
18511da177e4SLinus Torvalds 	if (1 == pcontrol)
18521da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
18531da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
18541da177e4SLinus Torvalds }
18551da177e4SLinus Torvalds 
18561da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
18571da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
18581da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
18591da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
18601da177e4SLinus Torvalds 
18611da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
18621da177e4SLinus Torvalds 	if (1 == pcontrol)
18631da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
18641da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
18651da177e4SLinus Torvalds }
18661da177e4SLinus Torvalds 
18671da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target)
18681da177e4SLinus Torvalds {       /* Format device page for mode_sense */
18691da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
18701da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
18711da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
18721da177e4SLinus Torvalds 
18731da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
18741da177e4SLinus Torvalds 	p[10] = (sdebug_sectors_per >> 8) & 0xff;
18751da177e4SLinus Torvalds 	p[11] = sdebug_sectors_per & 0xff;
1876597136abSMartin K. Petersen 	p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1877597136abSMartin K. Petersen 	p[13] = scsi_debug_sector_size & 0xff;
1878d986788bSMartin Pitt 	if (scsi_debug_removable)
18791da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
18801da177e4SLinus Torvalds 	if (1 == pcontrol)
18811da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
18821da177e4SLinus Torvalds 	return sizeof(format_pg);
18831da177e4SLinus Torvalds }
18841da177e4SLinus Torvalds 
18851da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
18861da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
1887cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1888cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1889cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
18901da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
18911da177e4SLinus Torvalds 
1892cbf67842SDouglas Gilbert 	if (SCSI_DEBUG_OPT_N_WCE & scsi_debug_opts)
1893cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
18941da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
18951da177e4SLinus Torvalds 	if (1 == pcontrol)
1896cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1897cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
1898cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
18991da177e4SLinus Torvalds 	return sizeof(caching_pg);
19001da177e4SLinus Torvalds }
19011da177e4SLinus Torvalds 
19021da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
19031da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
1904c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1905c65b1445SDouglas Gilbert 				        0, 0, 0, 0};
1906c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
19071da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
19081da177e4SLinus Torvalds 
19091da177e4SLinus Torvalds 	if (scsi_debug_dsense)
19101da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
1911c65b1445SDouglas Gilbert 	else
1912c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
1913c6a44287SMartin K. Petersen 
1914c6a44287SMartin K. Petersen 	if (scsi_debug_ato)
1915c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1916c6a44287SMartin K. Petersen 
19171da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
19181da177e4SLinus Torvalds 	if (1 == pcontrol)
1919c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1920c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1921c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
19221da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
19231da177e4SLinus Torvalds }
19241da177e4SLinus Torvalds 
1925c65b1445SDouglas Gilbert 
19261da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
19271da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
1928c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
19291da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
1930c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1931c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
1932c65b1445SDouglas Gilbert 
19331da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
19341da177e4SLinus Torvalds 	if (1 == pcontrol)
1935c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1936c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1937c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
19381da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
19391da177e4SLinus Torvalds }
19401da177e4SLinus Torvalds 
1941c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1942c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
1943c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1944c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1945c65b1445SDouglas Gilbert 
1946c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1947c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1948c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1949c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
1950c65b1445SDouglas Gilbert }
1951c65b1445SDouglas Gilbert 
1952c65b1445SDouglas Gilbert 
1953c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1954c65b1445SDouglas Gilbert 			      int target_dev_id)
1955c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
1956c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1957c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1958c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1959c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1960c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
1961c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1962c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1963c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1964c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1965c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1966c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
1967c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1968c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1969c65b1445SDouglas Gilbert 		};
1970c65b1445SDouglas Gilbert 	int port_a, port_b;
1971c65b1445SDouglas Gilbert 
1972c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1973c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1974c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1975c65b1445SDouglas Gilbert 	p[20] = (port_a >> 24);
1976c65b1445SDouglas Gilbert 	p[21] = (port_a >> 16) & 0xff;
1977c65b1445SDouglas Gilbert 	p[22] = (port_a >> 8) & 0xff;
1978c65b1445SDouglas Gilbert 	p[23] = port_a & 0xff;
1979c65b1445SDouglas Gilbert 	p[48 + 20] = (port_b >> 24);
1980c65b1445SDouglas Gilbert 	p[48 + 21] = (port_b >> 16) & 0xff;
1981c65b1445SDouglas Gilbert 	p[48 + 22] = (port_b >> 8) & 0xff;
1982c65b1445SDouglas Gilbert 	p[48 + 23] = port_b & 0xff;
1983c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1984c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1985c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
1986c65b1445SDouglas Gilbert }
1987c65b1445SDouglas Gilbert 
1988c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1989c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
1990c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1991c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1992c65b1445SDouglas Gilbert 		};
1993c65b1445SDouglas Gilbert 
1994c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1995c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1996c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1997c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
1998c65b1445SDouglas Gilbert }
1999c65b1445SDouglas Gilbert 
20001da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
20011da177e4SLinus Torvalds 
2002c2248fc9SDouglas Gilbert static int
2003c2248fc9SDouglas Gilbert resp_mode_sense(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
20041da177e4SLinus Torvalds {
200523183910SDouglas Gilbert 	unsigned char dbd, llbaa;
200623183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
20071da177e4SLinus Torvalds 	unsigned char dev_spec;
2008c2248fc9SDouglas Gilbert 	int k, alloc_len, msense_6, offset, len, target_dev_id;
2009c2248fc9SDouglas Gilbert 	int target = scp->device->id;
20101da177e4SLinus Torvalds 	unsigned char * ap;
20111da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
201201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
20131da177e4SLinus Torvalds 
201423183910SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);
20151da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
20161da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
20171da177e4SLinus Torvalds 	subpcode = cmd[3];
20181da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
201923183910SDouglas Gilbert 	llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
202023183910SDouglas Gilbert 	if ((0 == scsi_debug_ptype) && (0 == dbd))
202123183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
202223183910SDouglas Gilbert 	else
202323183910SDouglas Gilbert 		bd_len = 0;
20241da177e4SLinus Torvalds 	alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
20251da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
20261da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
2027cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
20281da177e4SLinus Torvalds 		return check_condition_result;
20291da177e4SLinus Torvalds 	}
2030c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2031c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
203223183910SDouglas Gilbert 	/* set DPOFUA bit for disks */
203323183910SDouglas Gilbert 	if (0 == scsi_debug_ptype)
203423183910SDouglas Gilbert 		dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
203523183910SDouglas Gilbert 	else
203623183910SDouglas Gilbert 		dev_spec = 0x0;
20371da177e4SLinus Torvalds 	if (msense_6) {
20381da177e4SLinus Torvalds 		arr[2] = dev_spec;
203923183910SDouglas Gilbert 		arr[3] = bd_len;
20401da177e4SLinus Torvalds 		offset = 4;
20411da177e4SLinus Torvalds 	} else {
20421da177e4SLinus Torvalds 		arr[3] = dev_spec;
204323183910SDouglas Gilbert 		if (16 == bd_len)
204423183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
204523183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
20461da177e4SLinus Torvalds 		offset = 8;
20471da177e4SLinus Torvalds 	}
20481da177e4SLinus Torvalds 	ap = arr + offset;
204928898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
205028898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
205128898873SFUJITA Tomonori 
205223183910SDouglas Gilbert 	if (8 == bd_len) {
205323183910SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe) {
205423183910SDouglas Gilbert 			ap[0] = 0xff;
205523183910SDouglas Gilbert 			ap[1] = 0xff;
205623183910SDouglas Gilbert 			ap[2] = 0xff;
205723183910SDouglas Gilbert 			ap[3] = 0xff;
205823183910SDouglas Gilbert 		} else {
205923183910SDouglas Gilbert 			ap[0] = (sdebug_capacity >> 24) & 0xff;
206023183910SDouglas Gilbert 			ap[1] = (sdebug_capacity >> 16) & 0xff;
206123183910SDouglas Gilbert 			ap[2] = (sdebug_capacity >> 8) & 0xff;
206223183910SDouglas Gilbert 			ap[3] = sdebug_capacity & 0xff;
206323183910SDouglas Gilbert 		}
2064597136abSMartin K. Petersen 		ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
2065597136abSMartin K. Petersen 		ap[7] = scsi_debug_sector_size & 0xff;
206623183910SDouglas Gilbert 		offset += bd_len;
206723183910SDouglas Gilbert 		ap = arr + offset;
206823183910SDouglas Gilbert 	} else if (16 == bd_len) {
206923183910SDouglas Gilbert 		unsigned long long capac = sdebug_capacity;
207023183910SDouglas Gilbert 
207123183910SDouglas Gilbert         	for (k = 0; k < 8; ++k, capac >>= 8)
207223183910SDouglas Gilbert                 	ap[7 - k] = capac & 0xff;
2073597136abSMartin K. Petersen 		ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
2074597136abSMartin K. Petersen 		ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
2075597136abSMartin K. Petersen 		ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
2076597136abSMartin K. Petersen 		ap[15] = scsi_debug_sector_size & 0xff;
207723183910SDouglas Gilbert 		offset += bd_len;
207823183910SDouglas Gilbert 		ap = arr + offset;
207923183910SDouglas Gilbert 	}
20801da177e4SLinus Torvalds 
2081c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2082c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
208322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
20841da177e4SLinus Torvalds 		return check_condition_result;
20851da177e4SLinus Torvalds 	}
20861da177e4SLinus Torvalds 	switch (pcode) {
20871da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
20881da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
20891da177e4SLinus Torvalds 		offset += len;
20901da177e4SLinus Torvalds 		break;
20911da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
20921da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
20931da177e4SLinus Torvalds 		offset += len;
20941da177e4SLinus Torvalds 		break;
20951da177e4SLinus Torvalds         case 0x3:       /* Format device page, direct access */
20961da177e4SLinus Torvalds                 len = resp_format_pg(ap, pcontrol, target);
20971da177e4SLinus Torvalds                 offset += len;
20981da177e4SLinus Torvalds                 break;
20991da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
21001da177e4SLinus Torvalds 		len = resp_caching_pg(ap, pcontrol, target);
21011da177e4SLinus Torvalds 		offset += len;
21021da177e4SLinus Torvalds 		break;
21031da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
21041da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
21051da177e4SLinus Torvalds 		offset += len;
21061da177e4SLinus Torvalds 		break;
2107c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2108c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
210922017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2110c65b1445SDouglas Gilbert 			return check_condition_result;
2111c65b1445SDouglas Gilbert 	        }
2112c65b1445SDouglas Gilbert 		len = 0;
2113c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2114c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2115c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2116c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2117c65b1445SDouglas Gilbert 						  target_dev_id);
2118c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2119c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2120c65b1445SDouglas Gilbert 		offset += len;
2121c65b1445SDouglas Gilbert 		break;
21221da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
21231da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
21241da177e4SLinus Torvalds 		offset += len;
21251da177e4SLinus Torvalds 		break;
21261da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2127c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
21281da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
21291da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
21301da177e4SLinus Torvalds 			len += resp_format_pg(ap + len, pcontrol, target);
21311da177e4SLinus Torvalds 			len += resp_caching_pg(ap + len, pcontrol, target);
21321da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2133c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2134c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2135c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2136c65b1445SDouglas Gilbert 						  target, target_dev_id);
2137c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2138c65b1445SDouglas Gilbert 			}
21391da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2140c65b1445SDouglas Gilbert 		} else {
214122017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2142c65b1445SDouglas Gilbert 			return check_condition_result;
2143c65b1445SDouglas Gilbert                 }
21441da177e4SLinus Torvalds 		offset += len;
21451da177e4SLinus Torvalds 		break;
21461da177e4SLinus Torvalds 	default:
214722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
21481da177e4SLinus Torvalds 		return check_condition_result;
21491da177e4SLinus Torvalds 	}
21501da177e4SLinus Torvalds 	if (msense_6)
21511da177e4SLinus Torvalds 		arr[0] = offset - 1;
21521da177e4SLinus Torvalds 	else {
21531da177e4SLinus Torvalds 		arr[0] = ((offset - 2) >> 8) & 0xff;
21541da177e4SLinus Torvalds 		arr[1] = (offset - 2) & 0xff;
21551da177e4SLinus Torvalds 	}
21561da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
21571da177e4SLinus Torvalds }
21581da177e4SLinus Torvalds 
2159c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2160c65b1445SDouglas Gilbert 
2161c2248fc9SDouglas Gilbert static int
2162c2248fc9SDouglas Gilbert resp_mode_select(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
2163c65b1445SDouglas Gilbert {
2164c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2165c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2166c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
216701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2168c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2169c65b1445SDouglas Gilbert 
2170c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2171c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2172c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2173c65b1445SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
2174c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
217522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2176c65b1445SDouglas Gilbert 		return check_condition_result;
2177c65b1445SDouglas Gilbert 	}
2178c65b1445SDouglas Gilbert         res = fetch_to_dev_buffer(scp, arr, param_len);
2179c65b1445SDouglas Gilbert         if (-1 == res)
2180c65b1445SDouglas Gilbert                 return (DID_ERROR << 16);
2181c65b1445SDouglas Gilbert         else if ((res < param_len) &&
2182c65b1445SDouglas Gilbert                  (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
2183cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2184cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2185cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2186c65b1445SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
2187c65b1445SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
218823183910SDouglas Gilbert 	if (md_len > 2) {
218922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2190c65b1445SDouglas Gilbert 		return check_condition_result;
2191c65b1445SDouglas Gilbert 	}
2192c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2193c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2194c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2195c65b1445SDouglas Gilbert 	if (ps) {
219622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2197c65b1445SDouglas Gilbert 		return check_condition_result;
2198c65b1445SDouglas Gilbert 	}
2199c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2200c65b1445SDouglas Gilbert 	pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
2201c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2202c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2203cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2204c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2205c65b1445SDouglas Gilbert 		return check_condition_result;
2206c65b1445SDouglas Gilbert 	}
2207c65b1445SDouglas Gilbert 	switch (mpage) {
2208cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2209cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2210cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2211cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2212cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2213cbf67842SDouglas Gilbert 		}
2214cbf67842SDouglas Gilbert 		break;
2215c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2216c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2217c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2218c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
2219c65b1445SDouglas Gilbert 			scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
2220cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2221c65b1445SDouglas Gilbert 		}
2222c65b1445SDouglas Gilbert 		break;
2223c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2224c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2225c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2226c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2227cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2228c65b1445SDouglas Gilbert 		}
2229c65b1445SDouglas Gilbert 		break;
2230c65b1445SDouglas Gilbert 	default:
2231c65b1445SDouglas Gilbert 		break;
2232c65b1445SDouglas Gilbert 	}
223322017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2234c65b1445SDouglas Gilbert 	return check_condition_result;
2235cbf67842SDouglas Gilbert set_mode_changed_ua:
2236cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2237cbf67842SDouglas Gilbert 	return 0;
2238c65b1445SDouglas Gilbert }
2239c65b1445SDouglas Gilbert 
2240c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr)
2241c65b1445SDouglas Gilbert {
2242c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2243c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2244c65b1445SDouglas Gilbert 		};
2245c65b1445SDouglas Gilbert 
2246c65b1445SDouglas Gilbert         memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2247c65b1445SDouglas Gilbert         return sizeof(temp_l_pg);
2248c65b1445SDouglas Gilbert }
2249c65b1445SDouglas Gilbert 
2250c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr)
2251c65b1445SDouglas Gilbert {
2252c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2253c65b1445SDouglas Gilbert 		};
2254c65b1445SDouglas Gilbert 
2255c65b1445SDouglas Gilbert         memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2256c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2257c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2258c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2259c65b1445SDouglas Gilbert 	}
2260c65b1445SDouglas Gilbert         return sizeof(ie_l_pg);
2261c65b1445SDouglas Gilbert }
2262c65b1445SDouglas Gilbert 
2263c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2264c65b1445SDouglas Gilbert 
2265c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp,
2266c65b1445SDouglas Gilbert                           struct sdebug_dev_info * devip)
2267c65b1445SDouglas Gilbert {
2268c2248fc9SDouglas Gilbert 	int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n;
2269c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
227001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2271c65b1445SDouglas Gilbert 
2272c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2273c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2274c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2275c65b1445SDouglas Gilbert 	if (ppc || sp) {
227622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2277c65b1445SDouglas Gilbert 		return check_condition_result;
2278c65b1445SDouglas Gilbert 	}
2279c65b1445SDouglas Gilbert 	pcontrol = (cmd[2] & 0xc0) >> 6;
2280c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
228123183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2282c65b1445SDouglas Gilbert 	alloc_len = (cmd[7] << 8) + cmd[8];
2283c65b1445SDouglas Gilbert 	arr[0] = pcode;
228423183910SDouglas Gilbert 	if (0 == subpcode) {
2285c65b1445SDouglas Gilbert 		switch (pcode) {
2286c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2287c65b1445SDouglas Gilbert 			n = 4;
2288c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2289c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2290c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2291c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2292c65b1445SDouglas Gilbert 			break;
2293c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2294c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2295c65b1445SDouglas Gilbert 			break;
2296c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2297c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2298c65b1445SDouglas Gilbert 			break;
2299c65b1445SDouglas Gilbert 		default:
230022017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2301c65b1445SDouglas Gilbert 			return check_condition_result;
2302c65b1445SDouglas Gilbert 		}
230323183910SDouglas Gilbert 	} else if (0xff == subpcode) {
230423183910SDouglas Gilbert 		arr[0] |= 0x40;
230523183910SDouglas Gilbert 		arr[1] = subpcode;
230623183910SDouglas Gilbert 		switch (pcode) {
230723183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
230823183910SDouglas Gilbert 			n = 4;
230923183910SDouglas Gilbert 			arr[n++] = 0x0;
231023183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
231123183910SDouglas Gilbert 			arr[n++] = 0x0;
231223183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
231323183910SDouglas Gilbert 			arr[n++] = 0xd;
231423183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
231523183910SDouglas Gilbert 			arr[n++] = 0x2f;
231623183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
231723183910SDouglas Gilbert 			arr[3] = n - 4;
231823183910SDouglas Gilbert 			break;
231923183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
232023183910SDouglas Gilbert 			n = 4;
232123183910SDouglas Gilbert 			arr[n++] = 0xd;
232223183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
232323183910SDouglas Gilbert 			arr[3] = n - 4;
232423183910SDouglas Gilbert 			break;
232523183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
232623183910SDouglas Gilbert 			n = 4;
232723183910SDouglas Gilbert 			arr[n++] = 0x2f;
232823183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
232923183910SDouglas Gilbert 			arr[3] = n - 4;
233023183910SDouglas Gilbert 			break;
233123183910SDouglas Gilbert 		default:
233222017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
233323183910SDouglas Gilbert 			return check_condition_result;
233423183910SDouglas Gilbert 		}
233523183910SDouglas Gilbert 	} else {
233622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
233723183910SDouglas Gilbert 		return check_condition_result;
233823183910SDouglas Gilbert 	}
2339c65b1445SDouglas Gilbert 	len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
2340c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
2341c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
2342c65b1445SDouglas Gilbert }
2343c65b1445SDouglas Gilbert 
2344cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp,
234519789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
23461da177e4SLinus Torvalds {
2347c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
234822017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
23491da177e4SLinus Torvalds 		return check_condition_result;
23501da177e4SLinus Torvalds 	}
2351c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2352c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
235322017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2354cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2355c65b1445SDouglas Gilbert 		return check_condition_result;
2356c65b1445SDouglas Gilbert 	}
235719789100SFUJITA Tomonori 	return 0;
235819789100SFUJITA Tomonori }
235919789100SFUJITA Tomonori 
2360a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
2361c2248fc9SDouglas Gilbert static int
2362c2248fc9SDouglas Gilbert do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num, bool do_write)
236319789100SFUJITA Tomonori {
236419789100SFUJITA Tomonori 	int ret;
2365c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2366a4517511SAkinobu Mita 	struct scsi_data_buffer *sdb;
2367a4517511SAkinobu Mita 	enum dma_data_direction dir;
236819789100SFUJITA Tomonori 
2369c2248fc9SDouglas Gilbert 	if (do_write) {
2370a4517511SAkinobu Mita 		sdb = scsi_out(scmd);
2371a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
2372a4517511SAkinobu Mita 	} else {
2373a4517511SAkinobu Mita 		sdb = scsi_in(scmd);
2374a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2375a4517511SAkinobu Mita 	}
2376a4517511SAkinobu Mita 
2377a4517511SAkinobu Mita 	if (!sdb->length)
2378a4517511SAkinobu Mita 		return 0;
2379a4517511SAkinobu Mita 	if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2380a4517511SAkinobu Mita 		return -1;
238119789100SFUJITA Tomonori 
238219789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
238319789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
238419789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
238519789100SFUJITA Tomonori 
2386386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2387a4517511SAkinobu Mita 		   fake_storep + (block * scsi_debug_sector_size),
2388386ecb12SDave Gordon 		   (num - rest) * scsi_debug_sector_size, 0, do_write);
2389a4517511SAkinobu Mita 	if (ret != (num - rest) * scsi_debug_sector_size)
2390a4517511SAkinobu Mita 		return ret;
2391a4517511SAkinobu Mita 
2392a4517511SAkinobu Mita 	if (rest) {
2393386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2394a4517511SAkinobu Mita 			    fake_storep, rest * scsi_debug_sector_size,
2395386ecb12SDave Gordon 			    (num - rest) * scsi_debug_sector_size, do_write);
2396a4517511SAkinobu Mita 	}
239719789100SFUJITA Tomonori 
239819789100SFUJITA Tomonori 	return ret;
239919789100SFUJITA Tomonori }
240019789100SFUJITA Tomonori 
240138d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of
240238d5c833SDouglas Gilbert  * arr into fake_store(lba,num) and return true. If comparison fails then
240338d5c833SDouglas Gilbert  * return false. */
240438d5c833SDouglas Gilbert static bool
240538d5c833SDouglas Gilbert comp_write_worker(u64 lba, u32 num, const u8 *arr)
240638d5c833SDouglas Gilbert {
240738d5c833SDouglas Gilbert 	bool res;
240838d5c833SDouglas Gilbert 	u64 block, rest = 0;
240938d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
241038d5c833SDouglas Gilbert 	u32 lb_size = scsi_debug_sector_size;
241138d5c833SDouglas Gilbert 
241238d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
241338d5c833SDouglas Gilbert 	if (block + num > store_blks)
241438d5c833SDouglas Gilbert 		rest = block + num - store_blks;
241538d5c833SDouglas Gilbert 
241638d5c833SDouglas Gilbert 	res = !memcmp(fake_storep + (block * lb_size), arr,
241738d5c833SDouglas Gilbert 		      (num - rest) * lb_size);
241838d5c833SDouglas Gilbert 	if (!res)
241938d5c833SDouglas Gilbert 		return res;
242038d5c833SDouglas Gilbert 	if (rest)
242138d5c833SDouglas Gilbert 		res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
242238d5c833SDouglas Gilbert 			     rest * lb_size);
242338d5c833SDouglas Gilbert 	if (!res)
242438d5c833SDouglas Gilbert 		return res;
242538d5c833SDouglas Gilbert 	arr += num * lb_size;
242638d5c833SDouglas Gilbert 	memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
242738d5c833SDouglas Gilbert 	if (rest)
242838d5c833SDouglas Gilbert 		memcpy(fake_storep, arr + ((num - rest) * lb_size),
242938d5c833SDouglas Gilbert 		       rest * lb_size);
243038d5c833SDouglas Gilbert 	return res;
243138d5c833SDouglas Gilbert }
243238d5c833SDouglas Gilbert 
243351d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2434beb40ea4SAkinobu Mita {
243551d648afSAkinobu Mita 	__be16 csum;
2436beb40ea4SAkinobu Mita 
243751d648afSAkinobu Mita 	if (scsi_debug_guard)
243851d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
243951d648afSAkinobu Mita 	else
2440beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
244151d648afSAkinobu Mita 
2442beb40ea4SAkinobu Mita 	return csum;
2443beb40ea4SAkinobu Mita }
2444beb40ea4SAkinobu Mita 
2445beb40ea4SAkinobu Mita static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
2446beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
2447beb40ea4SAkinobu Mita {
244851d648afSAkinobu Mita 	__be16 csum = dif_compute_csum(data, scsi_debug_sector_size);
2449beb40ea4SAkinobu Mita 
2450beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
2451c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
2452beb40ea4SAkinobu Mita 			(unsigned long)sector,
2453beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
2454beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
2455beb40ea4SAkinobu Mita 		return 0x01;
2456beb40ea4SAkinobu Mita 	}
2457beb40ea4SAkinobu Mita 	if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
2458beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
2459c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2460c1287970STomas Winkler 			(unsigned long)sector);
2461beb40ea4SAkinobu Mita 		return 0x03;
2462beb40ea4SAkinobu Mita 	}
2463beb40ea4SAkinobu Mita 	if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
2464beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
2465c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2466c1287970STomas Winkler 			(unsigned long)sector);
2467beb40ea4SAkinobu Mita 		return 0x03;
2468beb40ea4SAkinobu Mita 	}
2469beb40ea4SAkinobu Mita 	return 0;
2470beb40ea4SAkinobu Mita }
2471beb40ea4SAkinobu Mita 
2472bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
247365f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
2474c6a44287SMartin K. Petersen {
2475be4e11beSAkinobu Mita 	size_t resid;
2476c6a44287SMartin K. Petersen 	void *paddr;
247714faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
2478be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
2479c6a44287SMartin K. Petersen 
2480e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
2481e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
2482c6a44287SMartin K. Petersen 
2483be4e11beSAkinobu Mita 	sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2484be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2485be4e11beSAkinobu Mita 			(read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2486be4e11beSAkinobu Mita 
2487be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
2488be4e11beSAkinobu Mita 		size_t len = min(miter.length, resid);
248914faa944SAkinobu Mita 		void *start = dif_store(sector);
2490be4e11beSAkinobu Mita 		size_t rest = 0;
249114faa944SAkinobu Mita 
249214faa944SAkinobu Mita 		if (dif_store_end < start + len)
249314faa944SAkinobu Mita 			rest = start + len - dif_store_end;
2494c6a44287SMartin K. Petersen 
2495be4e11beSAkinobu Mita 		paddr = miter.addr;
249614faa944SAkinobu Mita 
249765f72f2aSAkinobu Mita 		if (read)
249865f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
249965f72f2aSAkinobu Mita 		else
250065f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
250165f72f2aSAkinobu Mita 
250265f72f2aSAkinobu Mita 		if (rest) {
250365f72f2aSAkinobu Mita 			if (read)
250414faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
250565f72f2aSAkinobu Mita 			else
250665f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
250765f72f2aSAkinobu Mita 		}
2508c6a44287SMartin K. Petersen 
2509e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
2510c6a44287SMartin K. Petersen 		resid -= len;
2511c6a44287SMartin K. Petersen 	}
2512be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
2513bb8c063cSAkinobu Mita }
2514c6a44287SMartin K. Petersen 
2515bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2516bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
2517bb8c063cSAkinobu Mita {
2518bb8c063cSAkinobu Mita 	unsigned int i;
2519bb8c063cSAkinobu Mita 	struct sd_dif_tuple *sdt;
2520bb8c063cSAkinobu Mita 	sector_t sector;
2521bb8c063cSAkinobu Mita 
2522c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
2523bb8c063cSAkinobu Mita 		int ret;
2524bb8c063cSAkinobu Mita 
2525bb8c063cSAkinobu Mita 		sector = start_sec + i;
2526bb8c063cSAkinobu Mita 		sdt = dif_store(sector);
2527bb8c063cSAkinobu Mita 
252851d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
2529bb8c063cSAkinobu Mita 			continue;
2530bb8c063cSAkinobu Mita 
2531bb8c063cSAkinobu Mita 		ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2532bb8c063cSAkinobu Mita 		if (ret) {
2533bb8c063cSAkinobu Mita 			dif_errors++;
2534bb8c063cSAkinobu Mita 			return ret;
2535bb8c063cSAkinobu Mita 		}
2536bb8c063cSAkinobu Mita 	}
2537bb8c063cSAkinobu Mita 
253865f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, true);
2539c6a44287SMartin K. Petersen 	dix_reads++;
2540c6a44287SMartin K. Petersen 
2541c6a44287SMartin K. Petersen 	return 0;
2542c6a44287SMartin K. Petersen }
2543c6a44287SMartin K. Petersen 
2544c2248fc9SDouglas Gilbert static int
2545c2248fc9SDouglas Gilbert resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
254619789100SFUJITA Tomonori {
2547c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2548c2248fc9SDouglas Gilbert 	u64 lba;
2549c2248fc9SDouglas Gilbert 	u32 num;
2550c2248fc9SDouglas Gilbert 	u32 ei_lba;
255119789100SFUJITA Tomonori 	unsigned long iflags;
255219789100SFUJITA Tomonori 	int ret;
2553c2248fc9SDouglas Gilbert 	bool check_prot;
255419789100SFUJITA Tomonori 
2555c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2556c2248fc9SDouglas Gilbert 	case READ_16:
2557c2248fc9SDouglas Gilbert 		ei_lba = 0;
2558c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2559c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2560c2248fc9SDouglas Gilbert 		check_prot = true;
2561c2248fc9SDouglas Gilbert 		break;
2562c2248fc9SDouglas Gilbert 	case READ_10:
2563c2248fc9SDouglas Gilbert 		ei_lba = 0;
2564c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2565c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2566c2248fc9SDouglas Gilbert 		check_prot = true;
2567c2248fc9SDouglas Gilbert 		break;
2568c2248fc9SDouglas Gilbert 	case READ_6:
2569c2248fc9SDouglas Gilbert 		ei_lba = 0;
2570c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2571c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2572c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2573c2248fc9SDouglas Gilbert 		check_prot = true;
2574c2248fc9SDouglas Gilbert 		break;
2575c2248fc9SDouglas Gilbert 	case READ_12:
2576c2248fc9SDouglas Gilbert 		ei_lba = 0;
2577c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2578c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2579c2248fc9SDouglas Gilbert 		check_prot = true;
2580c2248fc9SDouglas Gilbert 		break;
2581c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
2582c2248fc9SDouglas Gilbert 		ei_lba = 0;
2583c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2584c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2585c2248fc9SDouglas Gilbert 		check_prot = false;
2586c2248fc9SDouglas Gilbert 		break;
2587c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
2588c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2589c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2590c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2591c2248fc9SDouglas Gilbert 		check_prot = false;
2592c2248fc9SDouglas Gilbert 		break;
2593c2248fc9SDouglas Gilbert 	}
2594c2248fc9SDouglas Gilbert 	if (check_prot) {
2595c2248fc9SDouglas Gilbert 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
2596c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2597c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2598c2248fc9SDouglas Gilbert 			return check_condition_result;
2599c2248fc9SDouglas Gilbert 		}
2600c2248fc9SDouglas Gilbert 		if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
2601c2248fc9SDouglas Gilbert 		     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
2602c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2603c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2604c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2605c2248fc9SDouglas Gilbert 	}
2606c2248fc9SDouglas Gilbert 	if (sdebug_any_injecting_opt) {
2607c2248fc9SDouglas Gilbert 		struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2608c2248fc9SDouglas Gilbert 
2609c2248fc9SDouglas Gilbert 		if (ep->inj_short)
2610c2248fc9SDouglas Gilbert 			num /= 2;
2611c2248fc9SDouglas Gilbert 	}
2612c2248fc9SDouglas Gilbert 
2613c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2614c2248fc9SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
2615c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2616c2248fc9SDouglas Gilbert 		return check_condition_result;
2617c2248fc9SDouglas Gilbert 	}
2618c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2619c2248fc9SDouglas Gilbert 	if (num > sdebug_store_sectors) {
2620c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2621c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2622c2248fc9SDouglas Gilbert 		return check_condition_result;
2623c2248fc9SDouglas Gilbert 	}
262419789100SFUJITA Tomonori 
26251da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
262632f7ef73SDouglas Gilbert 	    (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
2627c65b1445SDouglas Gilbert 	    ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
2628c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
2629c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
2630c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
2631c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2632c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
263332f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
263432f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
2635c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
2636c65b1445SDouglas Gilbert 		}
2637c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
26381da177e4SLinus Torvalds 		return check_condition_result;
26391da177e4SLinus Torvalds 	}
2640c6a44287SMartin K. Petersen 
26416c78cc06SAkinobu Mita 	read_lock_irqsave(&atomic_rw, iflags);
26426c78cc06SAkinobu Mita 
2643c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2644c2248fc9SDouglas Gilbert 	if (scsi_debug_dix && scsi_prot_sg_count(scp)) {
2645c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
2646c6a44287SMartin K. Petersen 
2647c6a44287SMartin K. Petersen 		if (prot_ret) {
26486c78cc06SAkinobu Mita 			read_unlock_irqrestore(&atomic_rw, iflags);
2649c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
2650c6a44287SMartin K. Petersen 			return illegal_condition_result;
2651c6a44287SMartin K. Petersen 		}
2652c6a44287SMartin K. Petersen 	}
2653c6a44287SMartin K. Petersen 
2654c2248fc9SDouglas Gilbert 	ret = do_device_access(scp, lba, num, false);
26551da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
2656a4517511SAkinobu Mita 	if (ret == -1)
2657a4517511SAkinobu Mita 		return DID_ERROR << 16;
2658a4517511SAkinobu Mita 
2659c2248fc9SDouglas Gilbert 	scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
2660a4517511SAkinobu Mita 
2661c2248fc9SDouglas Gilbert 	if (sdebug_any_injecting_opt) {
2662c2248fc9SDouglas Gilbert 		struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2663c2248fc9SDouglas Gilbert 
2664c2248fc9SDouglas Gilbert 		if (ep->inj_recovered) {
2665c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
2666c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
2667c2248fc9SDouglas Gilbert 			return check_condition_result;
2668c2248fc9SDouglas Gilbert 		} else if (ep->inj_transport) {
2669c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND,
2670c2248fc9SDouglas Gilbert 					TRANSPORT_PROBLEM, ACK_NAK_TO);
2671c2248fc9SDouglas Gilbert 			return check_condition_result;
2672c2248fc9SDouglas Gilbert 		} else if (ep->inj_dif) {
2673c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
2674c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2675c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2676c2248fc9SDouglas Gilbert 		} else if (ep->inj_dix) {
2677c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2678c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2679c2248fc9SDouglas Gilbert 		}
2680c2248fc9SDouglas Gilbert 	}
2681a4517511SAkinobu Mita 	return 0;
26821da177e4SLinus Torvalds }
26831da177e4SLinus Torvalds 
268458a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len)
2685c6a44287SMartin K. Petersen {
2686cbf67842SDouglas Gilbert 	int i, j, n;
2687c6a44287SMartin K. Petersen 
2688cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
2689c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
2690cbf67842SDouglas Gilbert 		char b[128];
2691c6a44287SMartin K. Petersen 
2692cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
2693c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
2694c6a44287SMartin K. Petersen 
2695cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
2696cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2697cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
2698cbf67842SDouglas Gilbert 			else
2699cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2700cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
2701cbf67842SDouglas Gilbert 		}
2702cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
2703c6a44287SMartin K. Petersen 	}
2704c6a44287SMartin K. Petersen }
2705c6a44287SMartin K. Petersen 
2706c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
2707395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
2708c6a44287SMartin K. Petersen {
2709be4e11beSAkinobu Mita 	int ret;
2710c6a44287SMartin K. Petersen 	struct sd_dif_tuple *sdt;
2711be4e11beSAkinobu Mita 	void *daddr;
271265f72f2aSAkinobu Mita 	sector_t sector = start_sec;
2713c6a44287SMartin K. Petersen 	int ppage_offset;
2714be4e11beSAkinobu Mita 	int dpage_offset;
2715be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
2716be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
2717c6a44287SMartin K. Petersen 
2718c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
2719c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2720c6a44287SMartin K. Petersen 
2721be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2722be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
2723be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2724be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2725be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2726c6a44287SMartin K. Petersen 
2727be4e11beSAkinobu Mita 	/* For each protection page */
2728be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
2729be4e11beSAkinobu Mita 		dpage_offset = 0;
2730be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
2731be4e11beSAkinobu Mita 			ret = 0x01;
2732be4e11beSAkinobu Mita 			goto out;
2733c6a44287SMartin K. Petersen 		}
2734c6a44287SMartin K. Petersen 
2735be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
2736be4e11beSAkinobu Mita 		     ppage_offset += sizeof(struct sd_dif_tuple)) {
2737be4e11beSAkinobu Mita 			/* If we're at the end of the current
2738be4e11beSAkinobu Mita 			 * data page advance to the next one
2739be4e11beSAkinobu Mita 			 */
2740be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
2741be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
2742be4e11beSAkinobu Mita 					ret = 0x01;
2743be4e11beSAkinobu Mita 					goto out;
2744be4e11beSAkinobu Mita 				}
2745be4e11beSAkinobu Mita 				dpage_offset = 0;
2746be4e11beSAkinobu Mita 			}
2747c6a44287SMartin K. Petersen 
2748be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
2749be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
2750be4e11beSAkinobu Mita 
2751be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
2752beb40ea4SAkinobu Mita 			if (ret) {
2753be4e11beSAkinobu Mita 				dump_sector(daddr, scsi_debug_sector_size);
2754395cef03SMartin K. Petersen 				goto out;
2755395cef03SMartin K. Petersen 			}
2756395cef03SMartin K. Petersen 
2757c6a44287SMartin K. Petersen 			sector++;
2758395cef03SMartin K. Petersen 			ei_lba++;
2759be4e11beSAkinobu Mita 			dpage_offset += scsi_debug_sector_size;
2760c6a44287SMartin K. Petersen 		}
2761be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
2762be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
2763c6a44287SMartin K. Petersen 	}
2764be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2765c6a44287SMartin K. Petersen 
276665f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
2767c6a44287SMartin K. Petersen 	dix_writes++;
2768c6a44287SMartin K. Petersen 
2769c6a44287SMartin K. Petersen 	return 0;
2770c6a44287SMartin K. Petersen 
2771c6a44287SMartin K. Petersen out:
2772c6a44287SMartin K. Petersen 	dif_errors++;
2773be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
2774be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2775c6a44287SMartin K. Petersen 	return ret;
2776c6a44287SMartin K. Petersen }
2777c6a44287SMartin K. Petersen 
2778b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
2779b90ebc3dSAkinobu Mita {
2780b90ebc3dSAkinobu Mita 	if (scsi_debug_unmap_alignment) {
2781b90ebc3dSAkinobu Mita 		lba += scsi_debug_unmap_granularity -
2782b90ebc3dSAkinobu Mita 			scsi_debug_unmap_alignment;
2783b90ebc3dSAkinobu Mita 	}
278449413112SArnd Bergmann 	sector_div(lba, scsi_debug_unmap_granularity);
2785b90ebc3dSAkinobu Mita 
2786b90ebc3dSAkinobu Mita 	return lba;
2787b90ebc3dSAkinobu Mita }
2788b90ebc3dSAkinobu Mita 
2789b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
2790b90ebc3dSAkinobu Mita {
2791a027b5b9SAkinobu Mita 	sector_t lba = index * scsi_debug_unmap_granularity;
2792a027b5b9SAkinobu Mita 
2793a027b5b9SAkinobu Mita 	if (scsi_debug_unmap_alignment) {
2794a027b5b9SAkinobu Mita 		lba -= scsi_debug_unmap_granularity -
2795b90ebc3dSAkinobu Mita 			scsi_debug_unmap_alignment;
2796b90ebc3dSAkinobu Mita 	}
2797b90ebc3dSAkinobu Mita 
2798a027b5b9SAkinobu Mita 	return lba;
2799a027b5b9SAkinobu Mita }
2800a027b5b9SAkinobu Mita 
280144d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
280244d92694SMartin K. Petersen {
2803b90ebc3dSAkinobu Mita 	sector_t end;
2804b90ebc3dSAkinobu Mita 	unsigned int mapped;
2805b90ebc3dSAkinobu Mita 	unsigned long index;
2806b90ebc3dSAkinobu Mita 	unsigned long next;
280744d92694SMartin K. Petersen 
2808b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
2809b90ebc3dSAkinobu Mita 	mapped = test_bit(index, map_storep);
281044d92694SMartin K. Petersen 
281144d92694SMartin K. Petersen 	if (mapped)
2812b90ebc3dSAkinobu Mita 		next = find_next_zero_bit(map_storep, map_size, index);
281344d92694SMartin K. Petersen 	else
2814b90ebc3dSAkinobu Mita 		next = find_next_bit(map_storep, map_size, index);
281544d92694SMartin K. Petersen 
2816b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
281744d92694SMartin K. Petersen 	*num = end - lba;
281844d92694SMartin K. Petersen 
281944d92694SMartin K. Petersen 	return mapped;
282044d92694SMartin K. Petersen }
282144d92694SMartin K. Petersen 
282244d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
282344d92694SMartin K. Petersen {
282444d92694SMartin K. Petersen 	sector_t end = lba + len;
282544d92694SMartin K. Petersen 
282644d92694SMartin K. Petersen 	while (lba < end) {
2827b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
282844d92694SMartin K. Petersen 
2829b90ebc3dSAkinobu Mita 		if (index < map_size)
2830b90ebc3dSAkinobu Mita 			set_bit(index, map_storep);
283144d92694SMartin K. Petersen 
2832b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
283344d92694SMartin K. Petersen 	}
283444d92694SMartin K. Petersen }
283544d92694SMartin K. Petersen 
283644d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
283744d92694SMartin K. Petersen {
283844d92694SMartin K. Petersen 	sector_t end = lba + len;
283944d92694SMartin K. Petersen 
284044d92694SMartin K. Petersen 	while (lba < end) {
2841b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
284244d92694SMartin K. Petersen 
2843b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
2844b90ebc3dSAkinobu Mita 		    lba + scsi_debug_unmap_granularity <= end &&
2845b90ebc3dSAkinobu Mita 		    index < map_size) {
2846b90ebc3dSAkinobu Mita 			clear_bit(index, map_storep);
2847b90ebc3dSAkinobu Mita 			if (scsi_debug_lbprz) {
2848be1dd78dSEric Sandeen 				memset(fake_storep +
2849cc34a8e6SAkinobu Mita 				       lba * scsi_debug_sector_size, 0,
2850cc34a8e6SAkinobu Mita 				       scsi_debug_sector_size *
2851cc34a8e6SAkinobu Mita 				       scsi_debug_unmap_granularity);
2852be1dd78dSEric Sandeen 			}
2853e9926b43SAkinobu Mita 			if (dif_storep) {
2854e9926b43SAkinobu Mita 				memset(dif_storep + lba, 0xff,
2855e9926b43SAkinobu Mita 				       sizeof(*dif_storep) *
2856e9926b43SAkinobu Mita 				       scsi_debug_unmap_granularity);
2857e9926b43SAkinobu Mita 			}
2858b90ebc3dSAkinobu Mita 		}
2859b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
286044d92694SMartin K. Petersen 	}
286144d92694SMartin K. Petersen }
286244d92694SMartin K. Petersen 
2863c2248fc9SDouglas Gilbert static int
2864c2248fc9SDouglas Gilbert resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
28651da177e4SLinus Torvalds {
2866c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2867c2248fc9SDouglas Gilbert 	u64 lba;
2868c2248fc9SDouglas Gilbert 	u32 num;
2869c2248fc9SDouglas Gilbert 	u32 ei_lba;
28701da177e4SLinus Torvalds 	unsigned long iflags;
287119789100SFUJITA Tomonori 	int ret;
2872c2248fc9SDouglas Gilbert 	bool check_prot;
28731da177e4SLinus Torvalds 
2874c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2875c2248fc9SDouglas Gilbert 	case WRITE_16:
2876c2248fc9SDouglas Gilbert 		ei_lba = 0;
2877c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2878c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2879c2248fc9SDouglas Gilbert 		check_prot = true;
2880c2248fc9SDouglas Gilbert 		break;
2881c2248fc9SDouglas Gilbert 	case WRITE_10:
2882c2248fc9SDouglas Gilbert 		ei_lba = 0;
2883c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2884c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2885c2248fc9SDouglas Gilbert 		check_prot = true;
2886c2248fc9SDouglas Gilbert 		break;
2887c2248fc9SDouglas Gilbert 	case WRITE_6:
2888c2248fc9SDouglas Gilbert 		ei_lba = 0;
2889c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2890c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2891c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2892c2248fc9SDouglas Gilbert 		check_prot = true;
2893c2248fc9SDouglas Gilbert 		break;
2894c2248fc9SDouglas Gilbert 	case WRITE_12:
2895c2248fc9SDouglas Gilbert 		ei_lba = 0;
2896c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2897c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2898c2248fc9SDouglas Gilbert 		check_prot = true;
2899c2248fc9SDouglas Gilbert 		break;
2900c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
2901c2248fc9SDouglas Gilbert 		ei_lba = 0;
2902c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2903c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2904c2248fc9SDouglas Gilbert 		check_prot = false;
2905c2248fc9SDouglas Gilbert 		break;
2906c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
2907c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2908c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2909c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2910c2248fc9SDouglas Gilbert 		check_prot = false;
2911c2248fc9SDouglas Gilbert 		break;
2912c2248fc9SDouglas Gilbert 	}
2913c2248fc9SDouglas Gilbert 	if (check_prot) {
2914c2248fc9SDouglas Gilbert 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
2915c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2916c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2917c2248fc9SDouglas Gilbert 			return check_condition_result;
2918c2248fc9SDouglas Gilbert 		}
2919c2248fc9SDouglas Gilbert 		if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
2920c2248fc9SDouglas Gilbert 		     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
2921c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2922c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2923c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2924c2248fc9SDouglas Gilbert 	}
2925c2248fc9SDouglas Gilbert 
2926c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2927c2248fc9SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
2928c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2929c2248fc9SDouglas Gilbert 		return check_condition_result;
2930c2248fc9SDouglas Gilbert 	}
2931c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2932c2248fc9SDouglas Gilbert 	if (num > sdebug_store_sectors) {
2933c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2934c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2935c2248fc9SDouglas Gilbert 		return check_condition_result;
2936c2248fc9SDouglas Gilbert 	}
29371da177e4SLinus Torvalds 
29386c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
29396c78cc06SAkinobu Mita 
2940c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2941c2248fc9SDouglas Gilbert 	if (scsi_debug_dix && scsi_prot_sg_count(scp)) {
2942c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
2943c6a44287SMartin K. Petersen 
2944c6a44287SMartin K. Petersen 		if (prot_ret) {
29456c78cc06SAkinobu Mita 			write_unlock_irqrestore(&atomic_rw, iflags);
2946c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
2947c6a44287SMartin K. Petersen 			return illegal_condition_result;
2948c6a44287SMartin K. Petersen 		}
2949c6a44287SMartin K. Petersen 	}
2950c6a44287SMartin K. Petersen 
2951c2248fc9SDouglas Gilbert 	ret = do_device_access(scp, lba, num, true);
29529ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
295344d92694SMartin K. Petersen 		map_region(lba, num);
29541da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
295519789100SFUJITA Tomonori 	if (-1 == ret)
29561da177e4SLinus Torvalds 		return (DID_ERROR << 16);
2957597136abSMartin K. Petersen 	else if ((ret < (num * scsi_debug_sector_size)) &&
29581da177e4SLinus Torvalds 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
2959c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2960cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
2961cbf67842SDouglas Gilbert 			    my_name, num * scsi_debug_sector_size, ret);
296244d92694SMartin K. Petersen 
2963c2248fc9SDouglas Gilbert 	if (sdebug_any_injecting_opt) {
2964c2248fc9SDouglas Gilbert 		struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2965c2248fc9SDouglas Gilbert 
2966c2248fc9SDouglas Gilbert 		if (ep->inj_recovered) {
2967c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
2968c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
2969c2248fc9SDouglas Gilbert 			return check_condition_result;
2970c2248fc9SDouglas Gilbert 		} else if (ep->inj_dif) {
2971c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
2972c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2973c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2974c2248fc9SDouglas Gilbert 		} else if (ep->inj_dix) {
2975c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2976c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2977c2248fc9SDouglas Gilbert 		}
2978c2248fc9SDouglas Gilbert 	}
29791da177e4SLinus Torvalds 	return 0;
29801da177e4SLinus Torvalds }
29811da177e4SLinus Torvalds 
2982c2248fc9SDouglas Gilbert static int
2983c2248fc9SDouglas Gilbert resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, u32 ei_lba,
2984c2248fc9SDouglas Gilbert 		bool unmap, bool ndob)
298544d92694SMartin K. Petersen {
298644d92694SMartin K. Petersen 	unsigned long iflags;
298744d92694SMartin K. Petersen 	unsigned long long i;
298844d92694SMartin K. Petersen 	int ret;
298944d92694SMartin K. Petersen 
2990c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num);
299144d92694SMartin K. Petersen 	if (ret)
299244d92694SMartin K. Petersen 		return ret;
299344d92694SMartin K. Petersen 
299444d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
299544d92694SMartin K. Petersen 
29969ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
299744d92694SMartin K. Petersen 		unmap_region(lba, num);
299844d92694SMartin K. Petersen 		goto out;
299944d92694SMartin K. Petersen 	}
300044d92694SMartin K. Petersen 
3001c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
3002c2248fc9SDouglas Gilbert 	if (ndob) {
3003c2248fc9SDouglas Gilbert 		memset(fake_storep + (lba * scsi_debug_sector_size), 0,
3004c2248fc9SDouglas Gilbert 		       scsi_debug_sector_size);
3005c2248fc9SDouglas Gilbert 		ret = 0;
3006c2248fc9SDouglas Gilbert 	} else
3007c2248fc9SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fake_storep +
3008c2248fc9SDouglas Gilbert 					       (lba * scsi_debug_sector_size),
300944d92694SMartin K. Petersen 					  scsi_debug_sector_size);
301044d92694SMartin K. Petersen 
301144d92694SMartin K. Petersen 	if (-1 == ret) {
301244d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
301344d92694SMartin K. Petersen 		return (DID_ERROR << 16);
301444d92694SMartin K. Petersen 	} else if ((ret < (num * scsi_debug_sector_size)) &&
301544d92694SMartin K. Petersen 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
3016c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
3017cbf67842SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
3018cbf67842SDouglas Gilbert 			    my_name, "write same",
3019cbf67842SDouglas Gilbert 			    num * scsi_debug_sector_size, ret);
302044d92694SMartin K. Petersen 
302144d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
302244d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
302344d92694SMartin K. Petersen 		memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size),
302444d92694SMartin K. Petersen 		       fake_storep + (lba * scsi_debug_sector_size),
302544d92694SMartin K. Petersen 		       scsi_debug_sector_size);
302644d92694SMartin K. Petersen 
30279ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
302844d92694SMartin K. Petersen 		map_region(lba, num);
302944d92694SMartin K. Petersen out:
303044d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
303144d92694SMartin K. Petersen 
303244d92694SMartin K. Petersen 	return 0;
303344d92694SMartin K. Petersen }
303444d92694SMartin K. Petersen 
3035c2248fc9SDouglas Gilbert static int
3036c2248fc9SDouglas Gilbert resp_write_same_10(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
3037c2248fc9SDouglas Gilbert {
3038c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3039c2248fc9SDouglas Gilbert 	u32 lba;
3040c2248fc9SDouglas Gilbert 	u16 num;
3041c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3042c2248fc9SDouglas Gilbert 	bool unmap = false;
3043c2248fc9SDouglas Gilbert 
3044c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
3045c2248fc9SDouglas Gilbert 		if (scsi_debug_lbpws10 == 0) {
3046c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3047c2248fc9SDouglas Gilbert 			return check_condition_result;
3048c2248fc9SDouglas Gilbert 		} else
3049c2248fc9SDouglas Gilbert 			unmap = true;
3050c2248fc9SDouglas Gilbert 	}
3051c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3052c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3053c2248fc9SDouglas Gilbert 	if (num > scsi_debug_write_same_length) {
3054c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3055c2248fc9SDouglas Gilbert 		return check_condition_result;
3056c2248fc9SDouglas Gilbert 	}
3057c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3058c2248fc9SDouglas Gilbert }
3059c2248fc9SDouglas Gilbert 
3060c2248fc9SDouglas Gilbert static int
3061c2248fc9SDouglas Gilbert resp_write_same_16(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
3062c2248fc9SDouglas Gilbert {
3063c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3064c2248fc9SDouglas Gilbert 	u64 lba;
3065c2248fc9SDouglas Gilbert 	u32 num;
3066c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3067c2248fc9SDouglas Gilbert 	bool unmap = false;
3068c2248fc9SDouglas Gilbert 	bool ndob = false;
3069c2248fc9SDouglas Gilbert 
3070c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3071c2248fc9SDouglas Gilbert 		if (scsi_debug_lbpws == 0) {
3072c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3073c2248fc9SDouglas Gilbert 			return check_condition_result;
3074c2248fc9SDouglas Gilbert 		} else
3075c2248fc9SDouglas Gilbert 			unmap = true;
3076c2248fc9SDouglas Gilbert 	}
3077c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3078c2248fc9SDouglas Gilbert 		ndob = true;
3079c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3080c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3081c2248fc9SDouglas Gilbert 	if (num > scsi_debug_write_same_length) {
3082c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3083c2248fc9SDouglas Gilbert 		return check_condition_result;
3084c2248fc9SDouglas Gilbert 	}
3085c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3086c2248fc9SDouglas Gilbert }
3087c2248fc9SDouglas Gilbert 
3088acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3089acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3090acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3091acafd0b9SEwan D. Milne static int
3092acafd0b9SEwan D. Milne resp_write_buffer(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
3093acafd0b9SEwan D. Milne {
3094acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3095acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3096acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3097acafd0b9SEwan D. Milne 	u8 mode;
3098acafd0b9SEwan D. Milne 
3099acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3100acafd0b9SEwan D. Milne 	switch (mode) {
3101acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3102acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3103acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3104acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3105acafd0b9SEwan D. Milne 		break;
3106acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3107acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3108acafd0b9SEwan D. Milne 		break;
3109acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3110acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3111acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3112acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3113acafd0b9SEwan D. Milne 				    dev_list)
3114acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3115acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3116acafd0b9SEwan D. Milne 				if (devip != dp)
3117acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3118acafd0b9SEwan D. Milne 						dp->uas_bm);
3119acafd0b9SEwan D. Milne 			}
3120acafd0b9SEwan D. Milne 		break;
3121acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3122acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3123acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3124acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3125acafd0b9SEwan D. Milne 				    dev_list)
3126acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3127acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3128acafd0b9SEwan D. Milne 					dp->uas_bm);
3129acafd0b9SEwan D. Milne 		break;
3130acafd0b9SEwan D. Milne 	default:
3131acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3132acafd0b9SEwan D. Milne 		break;
3133acafd0b9SEwan D. Milne 	}
3134acafd0b9SEwan D. Milne 	return 0;
3135acafd0b9SEwan D. Milne }
3136acafd0b9SEwan D. Milne 
313738d5c833SDouglas Gilbert static int
313838d5c833SDouglas Gilbert resp_comp_write(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
313938d5c833SDouglas Gilbert {
314038d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
314138d5c833SDouglas Gilbert 	u8 *arr;
314238d5c833SDouglas Gilbert 	u8 *fake_storep_hold;
314338d5c833SDouglas Gilbert 	u64 lba;
314438d5c833SDouglas Gilbert 	u32 dnum;
314538d5c833SDouglas Gilbert 	u32 lb_size = scsi_debug_sector_size;
314638d5c833SDouglas Gilbert 	u8 num;
314738d5c833SDouglas Gilbert 	unsigned long iflags;
314838d5c833SDouglas Gilbert 	int ret;
3149d467d31fSDouglas Gilbert 	int retval = 0;
315038d5c833SDouglas Gilbert 
3151d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
315238d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
315338d5c833SDouglas Gilbert 	if (0 == num)
315438d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
315538d5c833SDouglas Gilbert 	if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
315638d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
315738d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
315838d5c833SDouglas Gilbert 		return check_condition_result;
315938d5c833SDouglas Gilbert 	}
316038d5c833SDouglas Gilbert 	if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
316138d5c833SDouglas Gilbert 	     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
316238d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
316338d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
316438d5c833SDouglas Gilbert 			    "to DIF device\n");
316538d5c833SDouglas Gilbert 
316638d5c833SDouglas Gilbert 	/* inline check_device_access_params() */
316738d5c833SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
316838d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
316938d5c833SDouglas Gilbert 		return check_condition_result;
317038d5c833SDouglas Gilbert 	}
317138d5c833SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
317238d5c833SDouglas Gilbert 	if (num > sdebug_store_sectors) {
317338d5c833SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
317438d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
317538d5c833SDouglas Gilbert 		return check_condition_result;
317638d5c833SDouglas Gilbert 	}
3177d467d31fSDouglas Gilbert 	dnum = 2 * num;
3178d467d31fSDouglas Gilbert 	arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3179d467d31fSDouglas Gilbert 	if (NULL == arr) {
3180d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3181d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3182d467d31fSDouglas Gilbert 		return check_condition_result;
3183d467d31fSDouglas Gilbert 	}
318438d5c833SDouglas Gilbert 
318538d5c833SDouglas Gilbert 	write_lock_irqsave(&atomic_rw, iflags);
318638d5c833SDouglas Gilbert 
318738d5c833SDouglas Gilbert 	/* trick do_device_access() to fetch both compare and write buffers
318838d5c833SDouglas Gilbert 	 * from data-in into arr. Safe (atomic) since write_lock held. */
318938d5c833SDouglas Gilbert 	fake_storep_hold = fake_storep;
319038d5c833SDouglas Gilbert 	fake_storep = arr;
319138d5c833SDouglas Gilbert 	ret = do_device_access(scp, 0, dnum, true);
319238d5c833SDouglas Gilbert 	fake_storep = fake_storep_hold;
319338d5c833SDouglas Gilbert 	if (ret == -1) {
3194d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3195d467d31fSDouglas Gilbert 		goto cleanup;
319638d5c833SDouglas Gilbert 	} else if ((ret < (dnum * lb_size)) &&
319738d5c833SDouglas Gilbert 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
319838d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
319938d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
320038d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
320138d5c833SDouglas Gilbert 	if (!comp_write_worker(lba, num, arr)) {
320238d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3203d467d31fSDouglas Gilbert 		retval = check_condition_result;
3204d467d31fSDouglas Gilbert 		goto cleanup;
320538d5c833SDouglas Gilbert 	}
320638d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
320738d5c833SDouglas Gilbert 		map_region(lba, num);
3208d467d31fSDouglas Gilbert cleanup:
320938d5c833SDouglas Gilbert 	write_unlock_irqrestore(&atomic_rw, iflags);
3210d467d31fSDouglas Gilbert 	kfree(arr);
3211d467d31fSDouglas Gilbert 	return retval;
321238d5c833SDouglas Gilbert }
321338d5c833SDouglas Gilbert 
321444d92694SMartin K. Petersen struct unmap_block_desc {
321544d92694SMartin K. Petersen 	__be64	lba;
321644d92694SMartin K. Petersen 	__be32	blocks;
321744d92694SMartin K. Petersen 	__be32	__reserved;
321844d92694SMartin K. Petersen };
321944d92694SMartin K. Petersen 
3220c2248fc9SDouglas Gilbert static int
3221c2248fc9SDouglas Gilbert resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
322244d92694SMartin K. Petersen {
322344d92694SMartin K. Petersen 	unsigned char *buf;
322444d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
322544d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
322644d92694SMartin K. Petersen 	int ret;
32276c78cc06SAkinobu Mita 	unsigned long iflags;
322844d92694SMartin K. Petersen 
322944d92694SMartin K. Petersen 
3230c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3231c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3232c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3233c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
323444d92694SMartin K. Petersen 
323544d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3236c2248fc9SDouglas Gilbert 	if (descriptors > scsi_debug_unmap_max_desc) {
3237c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
323844d92694SMartin K. Petersen 		return check_condition_result;
3239c2248fc9SDouglas Gilbert 	}
324044d92694SMartin K. Petersen 
3241c2248fc9SDouglas Gilbert 	buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
3242c2248fc9SDouglas Gilbert 	if (!buf) {
3243c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3244c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3245c2248fc9SDouglas Gilbert 		return check_condition_result;
3246c2248fc9SDouglas Gilbert 	}
3247c2248fc9SDouglas Gilbert 
3248c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
324944d92694SMartin K. Petersen 
325044d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
325144d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
325244d92694SMartin K. Petersen 
325344d92694SMartin K. Petersen 	desc = (void *)&buf[8];
325444d92694SMartin K. Petersen 
32556c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
32566c78cc06SAkinobu Mita 
325744d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
325844d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
325944d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
326044d92694SMartin K. Petersen 
3261c2248fc9SDouglas Gilbert 		ret = check_device_access_params(scp, lba, num);
326244d92694SMartin K. Petersen 		if (ret)
326344d92694SMartin K. Petersen 			goto out;
326444d92694SMartin K. Petersen 
326544d92694SMartin K. Petersen 		unmap_region(lba, num);
326644d92694SMartin K. Petersen 	}
326744d92694SMartin K. Petersen 
326844d92694SMartin K. Petersen 	ret = 0;
326944d92694SMartin K. Petersen 
327044d92694SMartin K. Petersen out:
32716c78cc06SAkinobu Mita 	write_unlock_irqrestore(&atomic_rw, iflags);
327244d92694SMartin K. Petersen 	kfree(buf);
327344d92694SMartin K. Petersen 
327444d92694SMartin K. Petersen 	return ret;
327544d92694SMartin K. Petersen }
327644d92694SMartin K. Petersen 
327744d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
327844d92694SMartin K. Petersen 
3279c2248fc9SDouglas Gilbert static int
3280c2248fc9SDouglas Gilbert resp_get_lba_status(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
328144d92694SMartin K. Petersen {
3282c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3283c2248fc9SDouglas Gilbert 	u64 lba;
3284c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
3285c2248fc9SDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
328644d92694SMartin K. Petersen 	int ret;
328744d92694SMartin K. Petersen 
3288c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3289c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
329044d92694SMartin K. Petersen 
329144d92694SMartin K. Petersen 	if (alloc_len < 24)
329244d92694SMartin K. Petersen 		return 0;
329344d92694SMartin K. Petersen 
3294c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, 1);
329544d92694SMartin K. Petersen 	if (ret)
329644d92694SMartin K. Petersen 		return ret;
329744d92694SMartin K. Petersen 
3298c2248fc9SDouglas Gilbert 	if (scsi_debug_lbp())
329944d92694SMartin K. Petersen 		mapped = map_state(lba, &num);
3300c2248fc9SDouglas Gilbert 	else {
3301c2248fc9SDouglas Gilbert 		mapped = 1;
3302c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
3303c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
3304c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
3305c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
3306c2248fc9SDouglas Gilbert 		else
3307c2248fc9SDouglas Gilbert 			num = 0xffffffff;
3308c2248fc9SDouglas Gilbert 	}
330944d92694SMartin K. Petersen 
331044d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
3311c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
3312c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
3313c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
3314c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
331544d92694SMartin K. Petersen 
3316c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
331744d92694SMartin K. Petersen }
331844d92694SMartin K. Petersen 
3319c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256
33201da177e4SLinus Torvalds 
33211da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp,
33221da177e4SLinus Torvalds 			    struct sdebug_dev_info * devip)
33231da177e4SLinus Torvalds {
33241da177e4SLinus Torvalds 	unsigned int alloc_len;
332522017ed2SDouglas Gilbert 	int lun_cnt, i, upper, num, n, want_wlun, shortish;
332622017ed2SDouglas Gilbert 	u64 lun;
332701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
33281da177e4SLinus Torvalds 	int select_report = (int)cmd[2];
33291da177e4SLinus Torvalds 	struct scsi_lun *one_lun;
33301da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_RLUN_ARR_SZ];
3331c65b1445SDouglas Gilbert 	unsigned char * max_addr;
33321da177e4SLinus Torvalds 
333319c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
33341da177e4SLinus Torvalds 	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
333522017ed2SDouglas Gilbert 	shortish = (alloc_len < 4);
333622017ed2SDouglas Gilbert 	if (shortish || (select_report > 2)) {
333722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, shortish ? 6 : 2, -1);
33381da177e4SLinus Torvalds 		return check_condition_result;
33391da177e4SLinus Torvalds 	}
33401da177e4SLinus Torvalds 	/* can produce response with up to 16k luns (lun 0 to lun 16383) */
33411da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
33421da177e4SLinus Torvalds 	lun_cnt = scsi_debug_max_luns;
3343c65b1445SDouglas Gilbert 	if (1 == select_report)
3344c65b1445SDouglas Gilbert 		lun_cnt = 0;
3345c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
3346c65b1445SDouglas Gilbert 		--lun_cnt;
334722017ed2SDouglas Gilbert 	want_wlun = (select_report > 0) ? 1 : 0;
334822017ed2SDouglas Gilbert 	num = lun_cnt + want_wlun;
3349c65b1445SDouglas Gilbert 	arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
3350c65b1445SDouglas Gilbert 	arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
3351c65b1445SDouglas Gilbert 	n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
3352c65b1445SDouglas Gilbert 			    sizeof(struct scsi_lun)), num);
3353c65b1445SDouglas Gilbert 	if (n < num) {
335422017ed2SDouglas Gilbert 		want_wlun = 0;
3355c65b1445SDouglas Gilbert 		lun_cnt = n;
3356c65b1445SDouglas Gilbert 	}
33571da177e4SLinus Torvalds 	one_lun = (struct scsi_lun *) &arr[8];
3358c65b1445SDouglas Gilbert 	max_addr = arr + SDEBUG_RLUN_ARR_SZ;
3359c65b1445SDouglas Gilbert 	for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
3360c65b1445SDouglas Gilbert              ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
3361c65b1445SDouglas Gilbert 	     i++, lun++) {
3362c65b1445SDouglas Gilbert 		upper = (lun >> 8) & 0x3f;
33631da177e4SLinus Torvalds 		if (upper)
33641da177e4SLinus Torvalds 			one_lun[i].scsi_lun[0] =
33651da177e4SLinus Torvalds 			    (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
3366c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = lun & 0xff;
33671da177e4SLinus Torvalds 	}
336822017ed2SDouglas Gilbert 	if (want_wlun) {
336934d55434STomas Winkler 		one_lun[i].scsi_lun[0] = (SCSI_W_LUN_REPORT_LUNS >> 8) & 0xff;
337034d55434STomas Winkler 		one_lun[i].scsi_lun[1] = SCSI_W_LUN_REPORT_LUNS & 0xff;
3371c65b1445SDouglas Gilbert 		i++;
3372c65b1445SDouglas Gilbert 	}
3373c65b1445SDouglas Gilbert 	alloc_len = (unsigned char *)(one_lun + i) - arr;
33741da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr,
33751da177e4SLinus Torvalds 				    min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
33761da177e4SLinus Torvalds }
33771da177e4SLinus Torvalds 
3378c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3379c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
3380c639d14eSFUJITA Tomonori {
3381be4e11beSAkinobu Mita 	int j;
3382c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
3383c639d14eSFUJITA Tomonori 	unsigned int offset;
3384c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
3385be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3386c639d14eSFUJITA Tomonori 
3387c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
3388c639d14eSFUJITA Tomonori 	buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
3389c5af0db9SAkinobu Mita 	if (!buf) {
339022017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
339122017ed2SDouglas Gilbert 				INSUFF_RES_ASCQ);
3392c5af0db9SAkinobu Mita 		return check_condition_result;
3393c5af0db9SAkinobu Mita 	}
3394c639d14eSFUJITA Tomonori 
339521a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
3396c639d14eSFUJITA Tomonori 
3397c639d14eSFUJITA Tomonori 	offset = 0;
3398be4e11beSAkinobu Mita 	sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3399be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_TO_SG);
3400c639d14eSFUJITA Tomonori 
3401be4e11beSAkinobu Mita 	while (sg_miter_next(&miter)) {
3402be4e11beSAkinobu Mita 		kaddr = miter.addr;
3403be4e11beSAkinobu Mita 		for (j = 0; j < miter.length; j++)
3404be4e11beSAkinobu Mita 			*(kaddr + j) ^= *(buf + offset + j);
3405c639d14eSFUJITA Tomonori 
3406be4e11beSAkinobu Mita 		offset += miter.length;
3407c639d14eSFUJITA Tomonori 	}
3408be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3409c639d14eSFUJITA Tomonori 	kfree(buf);
3410c639d14eSFUJITA Tomonori 
3411be4e11beSAkinobu Mita 	return 0;
3412c639d14eSFUJITA Tomonori }
3413c639d14eSFUJITA Tomonori 
3414c2248fc9SDouglas Gilbert static int
3415c2248fc9SDouglas Gilbert resp_xdwriteread_10(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
3416c2248fc9SDouglas Gilbert {
3417c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3418c2248fc9SDouglas Gilbert 	u64 lba;
3419c2248fc9SDouglas Gilbert 	u32 num;
3420c2248fc9SDouglas Gilbert 	int errsts;
3421c2248fc9SDouglas Gilbert 
3422c2248fc9SDouglas Gilbert 	if (!scsi_bidi_cmnd(scp)) {
3423c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3424c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3425c2248fc9SDouglas Gilbert 		return check_condition_result;
3426c2248fc9SDouglas Gilbert 	}
3427c2248fc9SDouglas Gilbert 	errsts = resp_read_dt0(scp, devip);
3428c2248fc9SDouglas Gilbert 	if (errsts)
3429c2248fc9SDouglas Gilbert 		return errsts;
3430c2248fc9SDouglas Gilbert 	if (!(cmd[1] & 0x4)) {		/* DISABLE_WRITE is not set */
3431c2248fc9SDouglas Gilbert 		errsts = resp_write_dt0(scp, devip);
3432c2248fc9SDouglas Gilbert 		if (errsts)
3433c2248fc9SDouglas Gilbert 			return errsts;
3434c2248fc9SDouglas Gilbert 	}
3435c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3436c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3437c2248fc9SDouglas Gilbert 	return resp_xdwriteread(scp, lba, num, devip);
3438c2248fc9SDouglas Gilbert }
3439c2248fc9SDouglas Gilbert 
3440cbf67842SDouglas Gilbert /* When timer or tasklet goes off this function is called. */
3441cbf67842SDouglas Gilbert static void sdebug_q_cmd_complete(unsigned long indx)
34421da177e4SLinus Torvalds {
3443cbf67842SDouglas Gilbert 	int qa_indx;
3444cbf67842SDouglas Gilbert 	int retiring = 0;
34451da177e4SLinus Torvalds 	unsigned long iflags;
3446cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3447cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
3448cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
34491da177e4SLinus Torvalds 
3450cbf67842SDouglas Gilbert 	atomic_inc(&sdebug_completions);
3451cbf67842SDouglas Gilbert 	qa_indx = indx;
3452cbf67842SDouglas Gilbert 	if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
3453c1287970STomas Winkler 		pr_err("wild qa_indx=%d\n", qa_indx);
34541da177e4SLinus Torvalds 		return;
34551da177e4SLinus Torvalds 	}
34561da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
3457cbf67842SDouglas Gilbert 	sqcp = &queued_arr[qa_indx];
3458cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
3459cbf67842SDouglas Gilbert 	if (NULL == scp) {
34601da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
3461c1287970STomas Winkler 		pr_err("scp is NULL\n");
34621da177e4SLinus Torvalds 		return;
34631da177e4SLinus Torvalds 	}
3464cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
3465cbf67842SDouglas Gilbert 	if (devip)
3466cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
3467cbf67842SDouglas Gilbert 	else
3468c1287970STomas Winkler 		pr_err("devip=NULL\n");
3469cbf67842SDouglas Gilbert 	if (atomic_read(&retired_max_queue) > 0)
3470cbf67842SDouglas Gilbert 		retiring = 1;
3471cbf67842SDouglas Gilbert 
3472cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
3473cbf67842SDouglas Gilbert 	if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
34741da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
3475c1287970STomas Winkler 		pr_err("Unexpected completion\n");
3476cbf67842SDouglas Gilbert 		return;
34771da177e4SLinus Torvalds 	}
34781da177e4SLinus Torvalds 
3479cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
3480cbf67842SDouglas Gilbert 		int k, retval;
3481cbf67842SDouglas Gilbert 
3482cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
3483cbf67842SDouglas Gilbert 		if (qa_indx >= retval) {
3484cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
3485c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
3486cbf67842SDouglas Gilbert 			return;
3487cbf67842SDouglas Gilbert 		}
3488cbf67842SDouglas Gilbert 		k = find_last_bit(queued_in_use_bm, retval);
3489cbf67842SDouglas Gilbert 		if ((k < scsi_debug_max_queue) || (k == retval))
3490cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3491cbf67842SDouglas Gilbert 		else
3492cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
3493cbf67842SDouglas Gilbert 	}
3494cbf67842SDouglas Gilbert 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
3495cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
3496cbf67842SDouglas Gilbert }
3497cbf67842SDouglas Gilbert 
3498cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
3499cbf67842SDouglas Gilbert static enum hrtimer_restart
3500cbf67842SDouglas Gilbert sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
3501cbf67842SDouglas Gilbert {
3502cbf67842SDouglas Gilbert 	int qa_indx;
3503cbf67842SDouglas Gilbert 	int retiring = 0;
3504cbf67842SDouglas Gilbert 	unsigned long iflags;
3505cbf67842SDouglas Gilbert 	struct sdebug_hrtimer *sd_hrtp = (struct sdebug_hrtimer *)timer;
3506cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3507cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
3508cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3509cbf67842SDouglas Gilbert 
3510cbf67842SDouglas Gilbert 	atomic_inc(&sdebug_completions);
3511cbf67842SDouglas Gilbert 	qa_indx = sd_hrtp->qa_indx;
3512cbf67842SDouglas Gilbert 	if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
3513c1287970STomas Winkler 		pr_err("wild qa_indx=%d\n", qa_indx);
3514cbf67842SDouglas Gilbert 		goto the_end;
3515cbf67842SDouglas Gilbert 	}
3516cbf67842SDouglas Gilbert 	spin_lock_irqsave(&queued_arr_lock, iflags);
3517cbf67842SDouglas Gilbert 	sqcp = &queued_arr[qa_indx];
3518cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
3519cbf67842SDouglas Gilbert 	if (NULL == scp) {
3520cbf67842SDouglas Gilbert 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
3521c1287970STomas Winkler 		pr_err("scp is NULL\n");
3522cbf67842SDouglas Gilbert 		goto the_end;
3523cbf67842SDouglas Gilbert 	}
3524cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
3525cbf67842SDouglas Gilbert 	if (devip)
3526cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
3527cbf67842SDouglas Gilbert 	else
3528c1287970STomas Winkler 		pr_err("devip=NULL\n");
3529cbf67842SDouglas Gilbert 	if (atomic_read(&retired_max_queue) > 0)
3530cbf67842SDouglas Gilbert 		retiring = 1;
3531cbf67842SDouglas Gilbert 
3532cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
3533cbf67842SDouglas Gilbert 	if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
3534cbf67842SDouglas Gilbert 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
3535c1287970STomas Winkler 		pr_err("Unexpected completion\n");
3536cbf67842SDouglas Gilbert 		goto the_end;
3537cbf67842SDouglas Gilbert 	}
3538cbf67842SDouglas Gilbert 
3539cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
3540cbf67842SDouglas Gilbert 		int k, retval;
3541cbf67842SDouglas Gilbert 
3542cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
3543cbf67842SDouglas Gilbert 		if (qa_indx >= retval) {
3544cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
3545c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
3546cbf67842SDouglas Gilbert 			goto the_end;
3547cbf67842SDouglas Gilbert 		}
3548cbf67842SDouglas Gilbert 		k = find_last_bit(queued_in_use_bm, retval);
3549cbf67842SDouglas Gilbert 		if ((k < scsi_debug_max_queue) || (k == retval))
3550cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3551cbf67842SDouglas Gilbert 		else
3552cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
3553cbf67842SDouglas Gilbert 	}
3554cbf67842SDouglas Gilbert 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
3555cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
3556cbf67842SDouglas Gilbert the_end:
3557cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
3558cbf67842SDouglas Gilbert }
35591da177e4SLinus Torvalds 
35608dea0d02SFUJITA Tomonori static struct sdebug_dev_info *
35618dea0d02SFUJITA Tomonori sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
35625cb2fc06SFUJITA Tomonori {
35635cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
35645cb2fc06SFUJITA Tomonori 
35655cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
35665cb2fc06SFUJITA Tomonori 	if (devip) {
35675cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
35685cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
35695cb2fc06SFUJITA Tomonori 	}
35705cb2fc06SFUJITA Tomonori 	return devip;
35715cb2fc06SFUJITA Tomonori }
35725cb2fc06SFUJITA Tomonori 
35731da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
35741da177e4SLinus Torvalds {
35751da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
35761da177e4SLinus Torvalds 	struct sdebug_dev_info * open_devip = NULL;
35771da177e4SLinus Torvalds 	struct sdebug_dev_info * devip =
35781da177e4SLinus Torvalds 			(struct sdebug_dev_info *)sdev->hostdata;
35791da177e4SLinus Torvalds 
35801da177e4SLinus Torvalds 	if (devip)
35811da177e4SLinus Torvalds 		return devip;
3582d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
35831da177e4SLinus Torvalds 	if (!sdbg_host) {
3584c1287970STomas Winkler 		pr_err("Host info NULL\n");
35851da177e4SLinus Torvalds 		return NULL;
35861da177e4SLinus Torvalds         }
35871da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
35881da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
35891da177e4SLinus Torvalds                     (devip->target == sdev->id) &&
35901da177e4SLinus Torvalds                     (devip->lun == sdev->lun))
35911da177e4SLinus Torvalds                         return devip;
35921da177e4SLinus Torvalds 		else {
35931da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
35941da177e4SLinus Torvalds 				open_devip = devip;
35951da177e4SLinus Torvalds 		}
35961da177e4SLinus Torvalds 	}
35975cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
35985cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
35995cb2fc06SFUJITA Tomonori 		if (!open_devip) {
3600c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
36011da177e4SLinus Torvalds 			return NULL;
36021da177e4SLinus Torvalds 		}
36031da177e4SLinus Torvalds 	}
3604a75869d1SFUJITA Tomonori 
36051da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
36061da177e4SLinus Torvalds 	open_devip->target = sdev->id;
36071da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
36081da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
3609cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
3610cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
3611c2248fc9SDouglas Gilbert 	open_devip->used = true;
36121da177e4SLinus Torvalds 	return open_devip;
36131da177e4SLinus Torvalds }
36141da177e4SLinus Torvalds 
36158dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
36161da177e4SLinus Torvalds {
36178dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3618c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
36198dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
362075ad23bcSNick Piggin 	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
36218dea0d02SFUJITA Tomonori 	return 0;
36228dea0d02SFUJITA Tomonori }
36231da177e4SLinus Torvalds 
36248dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
36258dea0d02SFUJITA Tomonori {
36268dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip;
3627a34c4e98SFUJITA Tomonori 
36281da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3629c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
36308dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
36318dea0d02SFUJITA Tomonori 	if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
36328dea0d02SFUJITA Tomonori 		sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
36338dea0d02SFUJITA Tomonori 	devip = devInfoReg(sdp);
36348dea0d02SFUJITA Tomonori 	if (NULL == devip)
36358dea0d02SFUJITA Tomonori 		return 1;	/* no resources, will be marked offline */
3636c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
36376bb5e6e7SAkinobu Mita 	blk_queue_max_segment_size(sdp->request_queue, -1U);
363878d4e5a0SDouglas Gilbert 	if (scsi_debug_no_uld)
363978d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
36408dea0d02SFUJITA Tomonori 	return 0;
36418dea0d02SFUJITA Tomonori }
36428dea0d02SFUJITA Tomonori 
36438dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
36448dea0d02SFUJITA Tomonori {
36458dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
36468dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
36478dea0d02SFUJITA Tomonori 
36488dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3649c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
36508dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
36518dea0d02SFUJITA Tomonori 	if (devip) {
365225985edcSLucas De Marchi 		/* make this slot available for re-use */
3653c2248fc9SDouglas Gilbert 		devip->used = false;
36548dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
36558dea0d02SFUJITA Tomonori 	}
36568dea0d02SFUJITA Tomonori }
36578dea0d02SFUJITA Tomonori 
3658cbf67842SDouglas Gilbert /* Returns 1 if cmnd found (deletes its timer or tasklet), else returns 0 */
36598dea0d02SFUJITA Tomonori static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
36608dea0d02SFUJITA Tomonori {
36618dea0d02SFUJITA Tomonori 	unsigned long iflags;
3662cbf67842SDouglas Gilbert 	int k, qmax, r_qmax;
36638dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3664cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
36658dea0d02SFUJITA Tomonori 
36668dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
3667cbf67842SDouglas Gilbert 	qmax = scsi_debug_max_queue;
3668cbf67842SDouglas Gilbert 	r_qmax = atomic_read(&retired_max_queue);
3669cbf67842SDouglas Gilbert 	if (r_qmax > qmax)
3670cbf67842SDouglas Gilbert 		qmax = r_qmax;
3671cbf67842SDouglas Gilbert 	for (k = 0; k < qmax; ++k) {
3672cbf67842SDouglas Gilbert 		if (test_bit(k, queued_in_use_bm)) {
36738dea0d02SFUJITA Tomonori 			sqcp = &queued_arr[k];
3674cbf67842SDouglas Gilbert 			if (cmnd == sqcp->a_cmnd) {
3675db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3676db525fceSDouglas Gilbert 					cmnd->device->hostdata;
3677db525fceSDouglas Gilbert 				if (devip)
3678db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3679db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3680db525fceSDouglas Gilbert 				spin_unlock_irqrestore(&queued_arr_lock,
3681db525fceSDouglas Gilbert 						       iflags);
3682cbf67842SDouglas Gilbert 				if (scsi_debug_ndelay > 0) {
3683cbf67842SDouglas Gilbert 					if (sqcp->sd_hrtp)
3684cbf67842SDouglas Gilbert 						hrtimer_cancel(
3685cbf67842SDouglas Gilbert 							&sqcp->sd_hrtp->hrt);
3686cbf67842SDouglas Gilbert 				} else if (scsi_debug_delay > 0) {
3687cbf67842SDouglas Gilbert 					if (sqcp->cmnd_timerp)
3688cbf67842SDouglas Gilbert 						del_timer_sync(
3689cbf67842SDouglas Gilbert 							sqcp->cmnd_timerp);
3690cbf67842SDouglas Gilbert 				} else if (scsi_debug_delay < 0) {
3691cbf67842SDouglas Gilbert 					if (sqcp->tletp)
3692cbf67842SDouglas Gilbert 						tasklet_kill(sqcp->tletp);
3693cbf67842SDouglas Gilbert 				}
3694db525fceSDouglas Gilbert 				clear_bit(k, queued_in_use_bm);
3695db525fceSDouglas Gilbert 				return 1;
36968dea0d02SFUJITA Tomonori 			}
36978dea0d02SFUJITA Tomonori 		}
3698cbf67842SDouglas Gilbert 	}
36998dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
3700db525fceSDouglas Gilbert 	return 0;
37018dea0d02SFUJITA Tomonori }
37028dea0d02SFUJITA Tomonori 
3703cbf67842SDouglas Gilbert /* Deletes (stops) timers or tasklets of all queued commands */
37048dea0d02SFUJITA Tomonori static void stop_all_queued(void)
37058dea0d02SFUJITA Tomonori {
37068dea0d02SFUJITA Tomonori 	unsigned long iflags;
37078dea0d02SFUJITA Tomonori 	int k;
37088dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3709cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
37108dea0d02SFUJITA Tomonori 
37118dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
3712cbf67842SDouglas Gilbert 	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3713cbf67842SDouglas Gilbert 		if (test_bit(k, queued_in_use_bm)) {
37148dea0d02SFUJITA Tomonori 			sqcp = &queued_arr[k];
3715cbf67842SDouglas Gilbert 			if (sqcp->a_cmnd) {
3716db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3717db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
3718db525fceSDouglas Gilbert 				if (devip)
3719db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3720db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3721db525fceSDouglas Gilbert 				spin_unlock_irqrestore(&queued_arr_lock,
3722db525fceSDouglas Gilbert 						       iflags);
3723cbf67842SDouglas Gilbert 				if (scsi_debug_ndelay > 0) {
3724cbf67842SDouglas Gilbert 					if (sqcp->sd_hrtp)
3725cbf67842SDouglas Gilbert 						hrtimer_cancel(
3726cbf67842SDouglas Gilbert 							&sqcp->sd_hrtp->hrt);
3727cbf67842SDouglas Gilbert 				} else if (scsi_debug_delay > 0) {
3728cbf67842SDouglas Gilbert 					if (sqcp->cmnd_timerp)
3729cbf67842SDouglas Gilbert 						del_timer_sync(
3730cbf67842SDouglas Gilbert 							sqcp->cmnd_timerp);
3731cbf67842SDouglas Gilbert 				} else if (scsi_debug_delay < 0) {
3732cbf67842SDouglas Gilbert 					if (sqcp->tletp)
3733cbf67842SDouglas Gilbert 						tasklet_kill(sqcp->tletp);
3734cbf67842SDouglas Gilbert 				}
3735db525fceSDouglas Gilbert 				clear_bit(k, queued_in_use_bm);
3736db525fceSDouglas Gilbert 				spin_lock_irqsave(&queued_arr_lock, iflags);
37378dea0d02SFUJITA Tomonori 			}
37388dea0d02SFUJITA Tomonori 		}
3739cbf67842SDouglas Gilbert 	}
3740cbf67842SDouglas Gilbert 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
3741cbf67842SDouglas Gilbert }
3742cbf67842SDouglas Gilbert 
3743cbf67842SDouglas Gilbert /* Free queued command memory on heap */
3744cbf67842SDouglas Gilbert static void free_all_queued(void)
3745cbf67842SDouglas Gilbert {
3746cbf67842SDouglas Gilbert 	unsigned long iflags;
3747cbf67842SDouglas Gilbert 	int k;
3748cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3749cbf67842SDouglas Gilbert 
3750cbf67842SDouglas Gilbert 	spin_lock_irqsave(&queued_arr_lock, iflags);
3751cbf67842SDouglas Gilbert 	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3752cbf67842SDouglas Gilbert 		sqcp = &queued_arr[k];
3753cbf67842SDouglas Gilbert 		kfree(sqcp->cmnd_timerp);
3754cbf67842SDouglas Gilbert 		sqcp->cmnd_timerp = NULL;
3755cbf67842SDouglas Gilbert 		kfree(sqcp->tletp);
3756cbf67842SDouglas Gilbert 		sqcp->tletp = NULL;
3757cbf67842SDouglas Gilbert 		kfree(sqcp->sd_hrtp);
3758cbf67842SDouglas Gilbert 		sqcp->sd_hrtp = NULL;
3759cbf67842SDouglas Gilbert 	}
37608dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
37611da177e4SLinus Torvalds }
37621da177e4SLinus Torvalds 
37631da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
37641da177e4SLinus Torvalds {
37651da177e4SLinus Torvalds 	++num_aborts;
3766cbf67842SDouglas Gilbert 	if (SCpnt) {
3767cbf67842SDouglas Gilbert 		if (SCpnt->device &&
3768cbf67842SDouglas Gilbert 		    (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts))
3769cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device, "%s\n",
3770cbf67842SDouglas Gilbert 				    __func__);
37711da177e4SLinus Torvalds 		stop_queued_cmnd(SCpnt);
3772cbf67842SDouglas Gilbert 	}
37731da177e4SLinus Torvalds 	return SUCCESS;
37741da177e4SLinus Torvalds }
37751da177e4SLinus Torvalds 
37761da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
37771da177e4SLinus Torvalds {
37781da177e4SLinus Torvalds 	struct sdebug_dev_info * devip;
37791da177e4SLinus Torvalds 
37801da177e4SLinus Torvalds 	++num_dev_resets;
3781cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
3782cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
3783cbf67842SDouglas Gilbert 
3784cbf67842SDouglas Gilbert 		if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)
3785cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3786cbf67842SDouglas Gilbert 		devip = devInfoReg(sdp);
37871da177e4SLinus Torvalds 		if (devip)
3788cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
37891da177e4SLinus Torvalds 	}
37901da177e4SLinus Torvalds 	return SUCCESS;
37911da177e4SLinus Torvalds }
37921da177e4SLinus Torvalds 
3793cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3794cbf67842SDouglas Gilbert {
3795cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
3796cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3797cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
3798cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
3799cbf67842SDouglas Gilbert 	int k = 0;
3800cbf67842SDouglas Gilbert 
3801cbf67842SDouglas Gilbert 	++num_target_resets;
3802cbf67842SDouglas Gilbert 	if (!SCpnt)
3803cbf67842SDouglas Gilbert 		goto lie;
3804cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
3805cbf67842SDouglas Gilbert 	if (!sdp)
3806cbf67842SDouglas Gilbert 		goto lie;
3807cbf67842SDouglas Gilbert 	if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)
3808cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3809cbf67842SDouglas Gilbert 	hp = sdp->host;
3810cbf67842SDouglas Gilbert 	if (!hp)
3811cbf67842SDouglas Gilbert 		goto lie;
3812cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3813cbf67842SDouglas Gilbert 	if (sdbg_host) {
3814cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
3815cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
3816cbf67842SDouglas Gilbert 				    dev_list)
3817cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
3818cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3819cbf67842SDouglas Gilbert 				++k;
3820cbf67842SDouglas Gilbert 			}
3821cbf67842SDouglas Gilbert 	}
3822cbf67842SDouglas Gilbert 	if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts)
3823cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3824cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
3825cbf67842SDouglas Gilbert lie:
3826cbf67842SDouglas Gilbert 	return SUCCESS;
3827cbf67842SDouglas Gilbert }
3828cbf67842SDouglas Gilbert 
38291da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
38301da177e4SLinus Torvalds {
38311da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
3832cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
38331da177e4SLinus Torvalds         struct scsi_device * sdp;
38341da177e4SLinus Torvalds         struct Scsi_Host * hp;
3835cbf67842SDouglas Gilbert 	int k = 0;
38361da177e4SLinus Torvalds 
38371da177e4SLinus Torvalds 	++num_bus_resets;
3838cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
3839cbf67842SDouglas Gilbert 		goto lie;
3840cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
3841cbf67842SDouglas Gilbert 	if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)
3842cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3843cbf67842SDouglas Gilbert 	hp = sdp->host;
3844cbf67842SDouglas Gilbert 	if (hp) {
3845d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
38461da177e4SLinus Torvalds 		if (sdbg_host) {
3847cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
38481da177e4SLinus Torvalds                                             &sdbg_host->dev_info_list,
3849cbf67842SDouglas Gilbert 					    dev_list) {
3850cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3851cbf67842SDouglas Gilbert 				++k;
38521da177e4SLinus Torvalds 			}
38531da177e4SLinus Torvalds 		}
3854cbf67842SDouglas Gilbert 	}
3855cbf67842SDouglas Gilbert 	if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts)
3856cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3857cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
3858cbf67842SDouglas Gilbert lie:
38591da177e4SLinus Torvalds 	return SUCCESS;
38601da177e4SLinus Torvalds }
38611da177e4SLinus Torvalds 
38621da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
38631da177e4SLinus Torvalds {
38641da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
3865cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3866cbf67842SDouglas Gilbert 	int k = 0;
38671da177e4SLinus Torvalds 
38681da177e4SLinus Torvalds 	++num_host_resets;
3869cbf67842SDouglas Gilbert 	if ((SCpnt->device) && (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts))
3870cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
38711da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
38721da177e4SLinus Torvalds         list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3873cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
3874cbf67842SDouglas Gilbert 				    dev_list) {
3875cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3876cbf67842SDouglas Gilbert 			++k;
3877cbf67842SDouglas Gilbert 		}
38781da177e4SLinus Torvalds         }
38791da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
38801da177e4SLinus Torvalds 	stop_all_queued();
3881cbf67842SDouglas Gilbert 	if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts)
3882cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
3883cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
38841da177e4SLinus Torvalds 	return SUCCESS;
38851da177e4SLinus Torvalds }
38861da177e4SLinus Torvalds 
3887f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
38885f2578e5SFUJITA Tomonori 				      unsigned long store_size)
38891da177e4SLinus Torvalds {
38901da177e4SLinus Torvalds 	struct partition * pp;
38911da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
38921da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
38931da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
38941da177e4SLinus Torvalds 
38951da177e4SLinus Torvalds 	/* assume partition table already zeroed */
3896f58b0efbSFUJITA Tomonori 	if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
38971da177e4SLinus Torvalds 		return;
38981da177e4SLinus Torvalds 	if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
38991da177e4SLinus Torvalds 		scsi_debug_num_parts = SDEBUG_MAX_PARTS;
3900c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
39011da177e4SLinus Torvalds 	}
3902c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
39031da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
39041da177e4SLinus Torvalds 			   / scsi_debug_num_parts;
39051da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
39061da177e4SLinus Torvalds         starts[0] = sdebug_sectors_per;
39071da177e4SLinus Torvalds 	for (k = 1; k < scsi_debug_num_parts; ++k)
39081da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
39091da177e4SLinus Torvalds 			    * heads_by_sects;
39101da177e4SLinus Torvalds 	starts[scsi_debug_num_parts] = num_sectors;
39111da177e4SLinus Torvalds 	starts[scsi_debug_num_parts + 1] = 0;
39121da177e4SLinus Torvalds 
39131da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
39141da177e4SLinus Torvalds 	ramp[511] = 0xAA;
39151da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
39161da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
39171da177e4SLinus Torvalds 		start_sec = starts[k];
39181da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
39191da177e4SLinus Torvalds 		pp->boot_ind = 0;
39201da177e4SLinus Torvalds 
39211da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
39221da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
39231da177e4SLinus Torvalds 			   / sdebug_sectors_per;
39241da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
39251da177e4SLinus Torvalds 
39261da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
39271da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
39281da177e4SLinus Torvalds 			       / sdebug_sectors_per;
39291da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
39301da177e4SLinus Torvalds 
3931150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
3932150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
39331da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
39341da177e4SLinus Torvalds 	}
39351da177e4SLinus Torvalds }
39361da177e4SLinus Torvalds 
3937cbf67842SDouglas Gilbert static int
3938cbf67842SDouglas Gilbert schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
3939cbf67842SDouglas Gilbert 	      int scsi_result, int delta_jiff)
39401da177e4SLinus Torvalds {
3941cbf67842SDouglas Gilbert 	unsigned long iflags;
3942cd62b7daSDouglas Gilbert 	int k, num_in_q, qdepth, inject;
3943cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp = NULL;
3944299b6c07STomas Winkler 	struct scsi_device *sdp;
39451da177e4SLinus Torvalds 
3946299b6c07STomas Winkler 	/* this should never happen */
3947299b6c07STomas Winkler 	if (WARN_ON(!cmnd))
3948299b6c07STomas Winkler 		return SCSI_MLQUEUE_HOST_BUSY;
3949299b6c07STomas Winkler 
3950299b6c07STomas Winkler 	if (NULL == devip) {
3951299b6c07STomas Winkler 		pr_warn("called devip == NULL\n");
3952cbf67842SDouglas Gilbert 		/* no particularly good error to report back */
3953cbf67842SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
39541da177e4SLinus Torvalds 	}
3955299b6c07STomas Winkler 
3956299b6c07STomas Winkler 	sdp = cmnd->device;
3957299b6c07STomas Winkler 
3958cbf67842SDouglas Gilbert 	if ((scsi_result) && (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
3959cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
3960cbf67842SDouglas Gilbert 			    __func__, scsi_result);
3961cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
3962cd62b7daSDouglas Gilbert 		goto respond_in_thread;
39631da177e4SLinus Torvalds 
3964cd62b7daSDouglas Gilbert 	/* schedule the response at a later time if resources permit */
39651da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
3966cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
3967cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
3968cbf67842SDouglas Gilbert 	inject = 0;
3969cd62b7daSDouglas Gilbert 	if ((qdepth > 0) && (num_in_q >= qdepth)) {
3970cd62b7daSDouglas Gilbert 		if (scsi_result) {
3971cd62b7daSDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
3972cd62b7daSDouglas Gilbert 			goto respond_in_thread;
3973cd62b7daSDouglas Gilbert 		} else
3974cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
3975cd62b7daSDouglas Gilbert 	} else if ((scsi_debug_every_nth != 0) &&
3976cd62b7daSDouglas Gilbert 		   (SCSI_DEBUG_OPT_RARE_TSF & scsi_debug_opts) &&
3977cd62b7daSDouglas Gilbert 		   (scsi_result == 0)) {
3978cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
3979cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
3980cbf67842SDouglas Gilbert 		     abs(scsi_debug_every_nth))) {
3981cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
3982cbf67842SDouglas Gilbert 			inject = 1;
3983cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
39841da177e4SLinus Torvalds 		}
3985cbf67842SDouglas Gilbert 	}
3986cbf67842SDouglas Gilbert 
3987cd62b7daSDouglas Gilbert 	k = find_first_zero_bit(queued_in_use_bm, scsi_debug_max_queue);
398878d4e5a0SDouglas Gilbert 	if (k >= scsi_debug_max_queue) {
39891da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
3990cd62b7daSDouglas Gilbert 		if (scsi_result)
3991cd62b7daSDouglas Gilbert 			goto respond_in_thread;
3992cd62b7daSDouglas Gilbert 		else if (SCSI_DEBUG_OPT_ALL_TSF & scsi_debug_opts)
3993cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
3994cbf67842SDouglas Gilbert 		if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts)
3995cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
3996cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
3997cd62b7daSDouglas Gilbert 				    __func__, scsi_debug_max_queue,
3998cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
3999cbf67842SDouglas Gilbert 						    "report: host busy"));
4000cd62b7daSDouglas Gilbert 		if (scsi_result)
4001cd62b7daSDouglas Gilbert 			goto respond_in_thread;
4002cd62b7daSDouglas Gilbert 		else
4003cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
40041da177e4SLinus Torvalds 	}
4005cbf67842SDouglas Gilbert 	__set_bit(k, queued_in_use_bm);
4006cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
4007cbf67842SDouglas Gilbert 	sqcp = &queued_arr[k];
40081da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
4009cbf67842SDouglas Gilbert 	cmnd->result = scsi_result;
40101da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
4011cbf67842SDouglas Gilbert 	if (delta_jiff > 0) {
4012cbf67842SDouglas Gilbert 		if (NULL == sqcp->cmnd_timerp) {
4013cbf67842SDouglas Gilbert 			sqcp->cmnd_timerp = kmalloc(sizeof(struct timer_list),
4014cbf67842SDouglas Gilbert 						    GFP_ATOMIC);
4015cbf67842SDouglas Gilbert 			if (NULL == sqcp->cmnd_timerp)
4016cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
4017cbf67842SDouglas Gilbert 			init_timer(sqcp->cmnd_timerp);
4018cbf67842SDouglas Gilbert 		}
4019cbf67842SDouglas Gilbert 		sqcp->cmnd_timerp->function = sdebug_q_cmd_complete;
4020cbf67842SDouglas Gilbert 		sqcp->cmnd_timerp->data = k;
4021cbf67842SDouglas Gilbert 		sqcp->cmnd_timerp->expires = get_jiffies_64() + delta_jiff;
4022cbf67842SDouglas Gilbert 		add_timer(sqcp->cmnd_timerp);
4023cbf67842SDouglas Gilbert 	} else if (scsi_debug_ndelay > 0) {
4024cbf67842SDouglas Gilbert 		ktime_t kt = ktime_set(0, scsi_debug_ndelay);
4025cbf67842SDouglas Gilbert 		struct sdebug_hrtimer *sd_hp = sqcp->sd_hrtp;
4026cbf67842SDouglas Gilbert 
4027cbf67842SDouglas Gilbert 		if (NULL == sd_hp) {
4028cbf67842SDouglas Gilbert 			sd_hp = kmalloc(sizeof(*sd_hp), GFP_ATOMIC);
4029cbf67842SDouglas Gilbert 			if (NULL == sd_hp)
4030cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
4031cbf67842SDouglas Gilbert 			sqcp->sd_hrtp = sd_hp;
4032cbf67842SDouglas Gilbert 			hrtimer_init(&sd_hp->hrt, CLOCK_MONOTONIC,
4033cbf67842SDouglas Gilbert 				     HRTIMER_MODE_REL);
4034cbf67842SDouglas Gilbert 			sd_hp->hrt.function = sdebug_q_cmd_hrt_complete;
4035cbf67842SDouglas Gilbert 			sd_hp->qa_indx = k;
4036cbf67842SDouglas Gilbert 		}
4037cbf67842SDouglas Gilbert 		hrtimer_start(&sd_hp->hrt, kt, HRTIMER_MODE_REL);
4038cbf67842SDouglas Gilbert 	} else {	/* delay < 0 */
4039cbf67842SDouglas Gilbert 		if (NULL == sqcp->tletp) {
4040cbf67842SDouglas Gilbert 			sqcp->tletp = kmalloc(sizeof(*sqcp->tletp),
4041cbf67842SDouglas Gilbert 					      GFP_ATOMIC);
4042cbf67842SDouglas Gilbert 			if (NULL == sqcp->tletp)
4043cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
4044cbf67842SDouglas Gilbert 			tasklet_init(sqcp->tletp,
4045cbf67842SDouglas Gilbert 				     sdebug_q_cmd_complete, k);
4046cbf67842SDouglas Gilbert 		}
4047cbf67842SDouglas Gilbert 		if (-1 == delta_jiff)
4048cbf67842SDouglas Gilbert 			tasklet_hi_schedule(sqcp->tletp);
4049cbf67842SDouglas Gilbert 		else
4050cbf67842SDouglas Gilbert 			tasklet_schedule(sqcp->tletp);
4051cbf67842SDouglas Gilbert 	}
4052cd62b7daSDouglas Gilbert 	if ((SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) &&
4053cd62b7daSDouglas Gilbert 	    (scsi_result == device_qfull_result))
4054cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
4055cbf67842SDouglas Gilbert 			    "%s: num_in_q=%d +1, %s%s\n", __func__,
4056cbf67842SDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""),
4057cbf67842SDouglas Gilbert 			    "status: TASK SET FULL");
40581da177e4SLinus Torvalds 	return 0;
4059cd62b7daSDouglas Gilbert 
4060cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
4061cd62b7daSDouglas Gilbert 	cmnd->result = scsi_result;
4062cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
4063cd62b7daSDouglas Gilbert 	return 0;
40641da177e4SLinus Torvalds }
4065cbf67842SDouglas Gilbert 
406623183910SDouglas Gilbert /* Note: The following macros create attribute files in the
406723183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
406823183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
406923183910SDouglas Gilbert    as it can when the corresponding attribute in the
407023183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
407123183910SDouglas Gilbert  */
4072c65b1445SDouglas Gilbert module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
40735b94e232SMartin K. Petersen module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
40740759c666SAkinobu Mita module_param_named(clustering, scsi_debug_clustering, bool, S_IRUGO | S_IWUSR);
4075c65b1445SDouglas Gilbert module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
4076c65b1445SDouglas Gilbert module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
40775b94e232SMartin K. Petersen module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
40785b94e232SMartin K. Petersen module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
4079c65b1445SDouglas Gilbert module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
4080c65b1445SDouglas Gilbert module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
408123183910SDouglas Gilbert module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
408268aee7baSAkinobu Mita module_param_named(guard, scsi_debug_guard, uint, S_IRUGO);
4083cbf67842SDouglas Gilbert module_param_named(host_lock, scsi_debug_host_lock, bool, S_IRUGO | S_IWUSR);
40845b94e232SMartin K. Petersen module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO);
40855b94e232SMartin K. Petersen module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO);
40865b94e232SMartin K. Petersen module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO);
4087be1dd78dSEric Sandeen module_param_named(lbprz, scsi_debug_lbprz, int, S_IRUGO);
40885b94e232SMartin K. Petersen module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
4089c65b1445SDouglas Gilbert module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
409078d4e5a0SDouglas Gilbert module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);
4091cbf67842SDouglas Gilbert module_param_named(ndelay, scsi_debug_ndelay, int, S_IRUGO | S_IWUSR);
4092c65b1445SDouglas Gilbert module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
409378d4e5a0SDouglas Gilbert module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);
4094c65b1445SDouglas Gilbert module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
4095c65b1445SDouglas Gilbert module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
40965b94e232SMartin K. Petersen module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO);
4097c65b1445SDouglas Gilbert module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
40985b94e232SMartin K. Petersen module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
4099c65b1445SDouglas Gilbert module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
4100d986788bSMartin Pitt module_param_named(removable, scsi_debug_removable, bool, S_IRUGO | S_IWUSR);
4101c65b1445SDouglas Gilbert module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
41025b94e232SMartin K. Petersen module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
4103c2248fc9SDouglas Gilbert module_param_named(strict, scsi_debug_strict, bool, S_IRUGO | S_IWUSR);
41045b94e232SMartin K. Petersen module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
41055b94e232SMartin K. Petersen module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
41065b94e232SMartin K. Petersen module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
41075b94e232SMartin K. Petersen module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
4108c65b1445SDouglas Gilbert module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
410923183910SDouglas Gilbert module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
411023183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
41115b94e232SMartin K. Petersen module_param_named(write_same_length, scsi_debug_write_same_length, int,
41125b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
41131da177e4SLinus Torvalds 
41141da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
41151da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
41161da177e4SLinus Torvalds MODULE_LICENSE("GPL");
41171da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION);
41181da177e4SLinus Torvalds 
41191da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
41205b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
41210759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
4122cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
4123c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
41245b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
41255b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
4126c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
4127beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
412823183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
41295b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
4130cbf67842SDouglas Gilbert MODULE_PARM_DESC(host_lock, "use host_lock around all commands (def=0)");
41315b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
41325b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
41335b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
4134be1dd78dSEric Sandeen MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
41355b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
4136c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
4137cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4138cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
4139c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
414078d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
41411da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
4142c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
414332c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
41446f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
41455b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
41461da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
4147d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
4148e46b0344SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])");
4149ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
4150c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
41515b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
41525b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
41536014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
41546014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
4155c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
41565b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
41575b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
41581da177e4SLinus Torvalds 
41591da177e4SLinus Torvalds static char sdebug_info[256];
41601da177e4SLinus Torvalds 
41611da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp)
41621da177e4SLinus Torvalds {
41631da177e4SLinus Torvalds 	sprintf(sdebug_info, "scsi_debug, version %s [%s], "
41641da177e4SLinus Torvalds 		"dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
41651da177e4SLinus Torvalds 		scsi_debug_version_date, scsi_debug_dev_size_mb,
41661da177e4SLinus Torvalds 		scsi_debug_opts);
41671da177e4SLinus Torvalds 	return sdebug_info;
41681da177e4SLinus Torvalds }
41691da177e4SLinus Torvalds 
4170cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
4171c8ed555aSAl Viro static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, int length)
41721da177e4SLinus Torvalds {
41731da177e4SLinus Torvalds 	char arr[16];
4174c8ed555aSAl Viro 	int opts;
41751da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
41761da177e4SLinus Torvalds 
41771da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
41781da177e4SLinus Torvalds 		return -EACCES;
41791da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
41801da177e4SLinus Torvalds 	arr[minLen] = '\0';
4181c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
41821da177e4SLinus Torvalds 		return -EINVAL;
4183c8ed555aSAl Viro 	scsi_debug_opts = opts;
41841da177e4SLinus Torvalds 	if (scsi_debug_every_nth != 0)
4185cbf67842SDouglas Gilbert 		atomic_set(&sdebug_cmnd_count, 0);
41861da177e4SLinus Torvalds 	return length;
41871da177e4SLinus Torvalds }
4188c8ed555aSAl Viro 
4189cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4190cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
4191cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
4192c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4193c8ed555aSAl Viro {
4194cbf67842SDouglas Gilbert 	int f, l;
4195cbf67842SDouglas Gilbert 	char b[32];
4196cbf67842SDouglas Gilbert 
4197cbf67842SDouglas Gilbert 	if (scsi_debug_every_nth > 0)
4198cbf67842SDouglas Gilbert 		snprintf(b, sizeof(b), " (curr:%d)",
4199cbf67842SDouglas Gilbert 			 ((SCSI_DEBUG_OPT_RARE_TSF & scsi_debug_opts) ?
4200cbf67842SDouglas Gilbert 				atomic_read(&sdebug_a_tsf) :
4201cbf67842SDouglas Gilbert 				atomic_read(&sdebug_cmnd_count)));
4202cbf67842SDouglas Gilbert 	else
4203cbf67842SDouglas Gilbert 		b[0] = '\0';
4204cbf67842SDouglas Gilbert 
4205cbf67842SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n"
42061da177e4SLinus Torvalds 		"num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
4207cbf67842SDouglas Gilbert 		"every_nth=%d%s\n"
4208cbf67842SDouglas Gilbert 		"delay=%d, ndelay=%d, max_luns=%d, q_completions=%d\n"
42091da177e4SLinus Torvalds 		"sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
4210cbf67842SDouglas Gilbert 		"command aborts=%d; RESETs: device=%d, target=%d, bus=%d, "
4211cbf67842SDouglas Gilbert 		"host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d "
4212cbf67842SDouglas Gilbert 		"usec_in_jiffy=%lu\n",
4213cbf67842SDouglas Gilbert 		SCSI_DEBUG_VERSION, scsi_debug_version_date,
4214cbf67842SDouglas Gilbert 		scsi_debug_num_tgts, scsi_debug_dev_size_mb, scsi_debug_opts,
4215cbf67842SDouglas Gilbert 		scsi_debug_every_nth, b, scsi_debug_delay, scsi_debug_ndelay,
4216cbf67842SDouglas Gilbert 		scsi_debug_max_luns, atomic_read(&sdebug_completions),
4217597136abSMartin K. Petersen 		scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
4218cbf67842SDouglas Gilbert 		sdebug_sectors_per, num_aborts, num_dev_resets,
4219cbf67842SDouglas Gilbert 		num_target_resets, num_bus_resets, num_host_resets,
4220cbf67842SDouglas Gilbert 		dix_reads, dix_writes, dif_errors, TICK_NSEC / 1000);
4221cbf67842SDouglas Gilbert 
4222cbf67842SDouglas Gilbert 	f = find_first_bit(queued_in_use_bm, scsi_debug_max_queue);
4223cbf67842SDouglas Gilbert 	if (f != scsi_debug_max_queue) {
4224cbf67842SDouglas Gilbert 		l = find_last_bit(queued_in_use_bm, scsi_debug_max_queue);
4225cbf67842SDouglas Gilbert 		seq_printf(m, "   %s BUSY: first,last bits set: %d,%d\n",
4226cbf67842SDouglas Gilbert 			   "queued_in_use_bm", f, l);
4227cbf67842SDouglas Gilbert 	}
4228c8ed555aSAl Viro 	return 0;
42291da177e4SLinus Torvalds }
42301da177e4SLinus Torvalds 
423182069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
42321da177e4SLinus Torvalds {
42331da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
42341da177e4SLinus Torvalds }
4235cbf67842SDouglas Gilbert /* Returns -EBUSY if delay is being changed and commands are queued */
423682069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
423782069379SAkinobu Mita 			   size_t count)
42381da177e4SLinus Torvalds {
4239cbf67842SDouglas Gilbert 	int delay, res;
42401da177e4SLinus Torvalds 
4241cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &delay))) {
4242cbf67842SDouglas Gilbert 		res = count;
4243cbf67842SDouglas Gilbert 		if (scsi_debug_delay != delay) {
4244cbf67842SDouglas Gilbert 			unsigned long iflags;
4245cbf67842SDouglas Gilbert 			int k;
4246cbf67842SDouglas Gilbert 
4247cbf67842SDouglas Gilbert 			spin_lock_irqsave(&queued_arr_lock, iflags);
4248cbf67842SDouglas Gilbert 			k = find_first_bit(queued_in_use_bm,
4249cbf67842SDouglas Gilbert 					   scsi_debug_max_queue);
4250cbf67842SDouglas Gilbert 			if (k != scsi_debug_max_queue)
4251cbf67842SDouglas Gilbert 				res = -EBUSY;	/* have queued commands */
4252cbf67842SDouglas Gilbert 			else {
42531da177e4SLinus Torvalds 				scsi_debug_delay = delay;
4254cbf67842SDouglas Gilbert 				scsi_debug_ndelay = 0;
42551da177e4SLinus Torvalds 			}
4256cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
4257cbf67842SDouglas Gilbert 		}
4258cbf67842SDouglas Gilbert 		return res;
42591da177e4SLinus Torvalds 	}
42601da177e4SLinus Torvalds 	return -EINVAL;
42611da177e4SLinus Torvalds }
426282069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
42631da177e4SLinus Torvalds 
4264cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4265cbf67842SDouglas Gilbert {
4266cbf67842SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ndelay);
4267cbf67842SDouglas Gilbert }
4268cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
4269cbf67842SDouglas Gilbert /* If > 0 and accepted then scsi_debug_delay is set to DELAY_OVERRIDDEN */
4270cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
4271cbf67842SDouglas Gilbert 			   size_t count)
4272cbf67842SDouglas Gilbert {
4273cbf67842SDouglas Gilbert 	unsigned long iflags;
4274cbf67842SDouglas Gilbert 	int ndelay, res, k;
4275cbf67842SDouglas Gilbert 
4276cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4277cbf67842SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < 1000000000)) {
4278cbf67842SDouglas Gilbert 		res = count;
4279cbf67842SDouglas Gilbert 		if (scsi_debug_ndelay != ndelay) {
4280cbf67842SDouglas Gilbert 			spin_lock_irqsave(&queued_arr_lock, iflags);
4281cbf67842SDouglas Gilbert 			k = find_first_bit(queued_in_use_bm,
4282cbf67842SDouglas Gilbert 					   scsi_debug_max_queue);
4283cbf67842SDouglas Gilbert 			if (k != scsi_debug_max_queue)
4284cbf67842SDouglas Gilbert 				res = -EBUSY;	/* have queued commands */
4285cbf67842SDouglas Gilbert 			else {
4286cbf67842SDouglas Gilbert 				scsi_debug_ndelay = ndelay;
4287cbf67842SDouglas Gilbert 				scsi_debug_delay = ndelay ? DELAY_OVERRIDDEN
4288cbf67842SDouglas Gilbert 							  : DEF_DELAY;
4289cbf67842SDouglas Gilbert 			}
4290cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
4291cbf67842SDouglas Gilbert 		}
4292cbf67842SDouglas Gilbert 		return res;
4293cbf67842SDouglas Gilbert 	}
4294cbf67842SDouglas Gilbert 	return -EINVAL;
4295cbf67842SDouglas Gilbert }
4296cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
4297cbf67842SDouglas Gilbert 
429882069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
42991da177e4SLinus Torvalds {
43001da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
43011da177e4SLinus Torvalds }
43021da177e4SLinus Torvalds 
430382069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
430482069379SAkinobu Mita 			  size_t count)
43051da177e4SLinus Torvalds {
43061da177e4SLinus Torvalds         int opts;
43071da177e4SLinus Torvalds 	char work[20];
43081da177e4SLinus Torvalds 
43091da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
431048a96876SRasmus Villemoes 		if (0 == strncasecmp(work,"0x", 2)) {
43111da177e4SLinus Torvalds 			if (1 == sscanf(&work[2], "%x", &opts))
43121da177e4SLinus Torvalds 				goto opts_done;
43131da177e4SLinus Torvalds 		} else {
43141da177e4SLinus Torvalds 			if (1 == sscanf(work, "%d", &opts))
43151da177e4SLinus Torvalds 				goto opts_done;
43161da177e4SLinus Torvalds 		}
43171da177e4SLinus Torvalds 	}
43181da177e4SLinus Torvalds 	return -EINVAL;
43191da177e4SLinus Torvalds opts_done:
43201da177e4SLinus Torvalds 	scsi_debug_opts = opts;
4321817fd66bSDouglas Gilbert 	if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts)
4322817fd66bSDouglas Gilbert 		sdebug_any_injecting_opt = true;
4323817fd66bSDouglas Gilbert 	else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts)
4324817fd66bSDouglas Gilbert 		sdebug_any_injecting_opt = true;
4325817fd66bSDouglas Gilbert 	else if (SCSI_DEBUG_OPT_DIF_ERR & opts)
4326817fd66bSDouglas Gilbert 		sdebug_any_injecting_opt = true;
4327817fd66bSDouglas Gilbert 	else if (SCSI_DEBUG_OPT_DIX_ERR & opts)
4328817fd66bSDouglas Gilbert 		sdebug_any_injecting_opt = true;
4329817fd66bSDouglas Gilbert 	else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts)
4330817fd66bSDouglas Gilbert 		sdebug_any_injecting_opt = true;
4331cbf67842SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
4332cbf67842SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
43331da177e4SLinus Torvalds 	return count;
43341da177e4SLinus Torvalds }
433582069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
43361da177e4SLinus Torvalds 
433782069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
43381da177e4SLinus Torvalds {
43391da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
43401da177e4SLinus Torvalds }
434182069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
434282069379SAkinobu Mita 			   size_t count)
43431da177e4SLinus Torvalds {
43441da177e4SLinus Torvalds         int n;
43451da177e4SLinus Torvalds 
43461da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
43471da177e4SLinus Torvalds 		scsi_debug_ptype = n;
43481da177e4SLinus Torvalds 		return count;
43491da177e4SLinus Torvalds 	}
43501da177e4SLinus Torvalds 	return -EINVAL;
43511da177e4SLinus Torvalds }
435282069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
43531da177e4SLinus Torvalds 
435482069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
43551da177e4SLinus Torvalds {
43561da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
43571da177e4SLinus Torvalds }
435882069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
435982069379SAkinobu Mita 			    size_t count)
43601da177e4SLinus Torvalds {
43611da177e4SLinus Torvalds         int n;
43621da177e4SLinus Torvalds 
43631da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
43641da177e4SLinus Torvalds 		scsi_debug_dsense = n;
43651da177e4SLinus Torvalds 		return count;
43661da177e4SLinus Torvalds 	}
43671da177e4SLinus Torvalds 	return -EINVAL;
43681da177e4SLinus Torvalds }
436982069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
43701da177e4SLinus Torvalds 
437182069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
437223183910SDouglas Gilbert {
437323183910SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
437423183910SDouglas Gilbert }
437582069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
437682069379SAkinobu Mita 			     size_t count)
437723183910SDouglas Gilbert {
437823183910SDouglas Gilbert         int n;
437923183910SDouglas Gilbert 
438023183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4381cbf67842SDouglas Gilbert 		n = (n > 0);
4382cbf67842SDouglas Gilbert 		scsi_debug_fake_rw = (scsi_debug_fake_rw > 0);
4383cbf67842SDouglas Gilbert 		if (scsi_debug_fake_rw != n) {
4384cbf67842SDouglas Gilbert 			if ((0 == n) && (NULL == fake_storep)) {
4385cbf67842SDouglas Gilbert 				unsigned long sz =
4386cbf67842SDouglas Gilbert 					(unsigned long)scsi_debug_dev_size_mb *
4387cbf67842SDouglas Gilbert 					1048576;
4388cbf67842SDouglas Gilbert 
4389cbf67842SDouglas Gilbert 				fake_storep = vmalloc(sz);
4390cbf67842SDouglas Gilbert 				if (NULL == fake_storep) {
4391c1287970STomas Winkler 					pr_err("out of memory, 9\n");
4392cbf67842SDouglas Gilbert 					return -ENOMEM;
4393cbf67842SDouglas Gilbert 				}
4394cbf67842SDouglas Gilbert 				memset(fake_storep, 0, sz);
4395cbf67842SDouglas Gilbert 			}
439623183910SDouglas Gilbert 			scsi_debug_fake_rw = n;
4397cbf67842SDouglas Gilbert 		}
439823183910SDouglas Gilbert 		return count;
439923183910SDouglas Gilbert 	}
440023183910SDouglas Gilbert 	return -EINVAL;
440123183910SDouglas Gilbert }
440282069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
440323183910SDouglas Gilbert 
440482069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
4405c65b1445SDouglas Gilbert {
4406c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
4407c65b1445SDouglas Gilbert }
440882069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
440982069379SAkinobu Mita 			      size_t count)
4410c65b1445SDouglas Gilbert {
4411c65b1445SDouglas Gilbert         int n;
4412c65b1445SDouglas Gilbert 
4413c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4414c65b1445SDouglas Gilbert 		scsi_debug_no_lun_0 = n;
4415c65b1445SDouglas Gilbert 		return count;
4416c65b1445SDouglas Gilbert 	}
4417c65b1445SDouglas Gilbert 	return -EINVAL;
4418c65b1445SDouglas Gilbert }
441982069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
4420c65b1445SDouglas Gilbert 
442182069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
44221da177e4SLinus Torvalds {
44231da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
44241da177e4SLinus Torvalds }
442582069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
442682069379SAkinobu Mita 			      size_t count)
44271da177e4SLinus Torvalds {
44281da177e4SLinus Torvalds         int n;
44291da177e4SLinus Torvalds 
44301da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
44311da177e4SLinus Torvalds 		scsi_debug_num_tgts = n;
44321da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
44331da177e4SLinus Torvalds 		return count;
44341da177e4SLinus Torvalds 	}
44351da177e4SLinus Torvalds 	return -EINVAL;
44361da177e4SLinus Torvalds }
443782069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
44381da177e4SLinus Torvalds 
443982069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
44401da177e4SLinus Torvalds {
44411da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
44421da177e4SLinus Torvalds }
444382069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
44441da177e4SLinus Torvalds 
444582069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
44461da177e4SLinus Torvalds {
44471da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
44481da177e4SLinus Torvalds }
444982069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
44501da177e4SLinus Torvalds 
445182069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
44521da177e4SLinus Torvalds {
44531da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
44541da177e4SLinus Torvalds }
445582069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
445682069379SAkinobu Mita 			       size_t count)
44571da177e4SLinus Torvalds {
44581da177e4SLinus Torvalds         int nth;
44591da177e4SLinus Torvalds 
44601da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
44611da177e4SLinus Torvalds 		scsi_debug_every_nth = nth;
4462cbf67842SDouglas Gilbert 		atomic_set(&sdebug_cmnd_count, 0);
44631da177e4SLinus Torvalds 		return count;
44641da177e4SLinus Torvalds 	}
44651da177e4SLinus Torvalds 	return -EINVAL;
44661da177e4SLinus Torvalds }
446782069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
44681da177e4SLinus Torvalds 
446982069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
44701da177e4SLinus Torvalds {
44711da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
44721da177e4SLinus Torvalds }
447382069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
447482069379SAkinobu Mita 			      size_t count)
44751da177e4SLinus Torvalds {
44761da177e4SLinus Torvalds         int n;
447719c8ead7SEwan D. Milne 	bool changed;
44781da177e4SLinus Torvalds 
44791da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
448019c8ead7SEwan D. Milne 		changed = (scsi_debug_max_luns != n);
44811da177e4SLinus Torvalds 		scsi_debug_max_luns = n;
44821da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
448319c8ead7SEwan D. Milne 		if (changed && (scsi_debug_scsi_level >= 5)) {	/* >= SPC-3 */
448419c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
448519c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
448619c8ead7SEwan D. Milne 
448719c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
448819c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
448919c8ead7SEwan D. Milne 					    host_list) {
449019c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
449119c8ead7SEwan D. Milne 						    dev_list) {
449219c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
449319c8ead7SEwan D. Milne 						dp->uas_bm);
449419c8ead7SEwan D. Milne 				}
449519c8ead7SEwan D. Milne 			}
449619c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
449719c8ead7SEwan D. Milne 		}
44981da177e4SLinus Torvalds 		return count;
44991da177e4SLinus Torvalds 	}
45001da177e4SLinus Torvalds 	return -EINVAL;
45011da177e4SLinus Torvalds }
450282069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
45031da177e4SLinus Torvalds 
450482069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
450578d4e5a0SDouglas Gilbert {
450678d4e5a0SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue);
450778d4e5a0SDouglas Gilbert }
4508cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
4509cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
451082069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
451182069379SAkinobu Mita 			       size_t count)
451278d4e5a0SDouglas Gilbert {
4513cbf67842SDouglas Gilbert 	unsigned long iflags;
4514cbf67842SDouglas Gilbert 	int n, k;
451578d4e5a0SDouglas Gilbert 
451678d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
451778d4e5a0SDouglas Gilbert 	    (n <= SCSI_DEBUG_CANQUEUE)) {
4518cbf67842SDouglas Gilbert 		spin_lock_irqsave(&queued_arr_lock, iflags);
4519cbf67842SDouglas Gilbert 		k = find_last_bit(queued_in_use_bm, SCSI_DEBUG_CANQUEUE);
452078d4e5a0SDouglas Gilbert 		scsi_debug_max_queue = n;
4521cbf67842SDouglas Gilbert 		if (SCSI_DEBUG_CANQUEUE == k)
4522cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4523cbf67842SDouglas Gilbert 		else if (k >= n)
4524cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4525cbf67842SDouglas Gilbert 		else
4526cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4527cbf67842SDouglas Gilbert 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
452878d4e5a0SDouglas Gilbert 		return count;
452978d4e5a0SDouglas Gilbert 	}
453078d4e5a0SDouglas Gilbert 	return -EINVAL;
453178d4e5a0SDouglas Gilbert }
453282069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
453378d4e5a0SDouglas Gilbert 
453482069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
453578d4e5a0SDouglas Gilbert {
453678d4e5a0SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld);
453778d4e5a0SDouglas Gilbert }
453882069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
453978d4e5a0SDouglas Gilbert 
454082069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
45411da177e4SLinus Torvalds {
45421da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
45431da177e4SLinus Torvalds }
454482069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
45451da177e4SLinus Torvalds 
454682069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
4547c65b1445SDouglas Gilbert {
4548c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
4549c65b1445SDouglas Gilbert }
455082069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
455182069379SAkinobu Mita 				size_t count)
4552c65b1445SDouglas Gilbert {
4553c65b1445SDouglas Gilbert         int n;
45540d01c5dfSDouglas Gilbert 	bool changed;
4555c65b1445SDouglas Gilbert 
4556c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
45570d01c5dfSDouglas Gilbert 		changed = (scsi_debug_virtual_gb != n);
4558c65b1445SDouglas Gilbert 		scsi_debug_virtual_gb = n;
455928898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
45600d01c5dfSDouglas Gilbert 		if (changed) {
45610d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
45620d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
456328898873SFUJITA Tomonori 
45644bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
45650d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
45660d01c5dfSDouglas Gilbert 					    host_list) {
45670d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
45680d01c5dfSDouglas Gilbert 						    dev_list) {
45690d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
45700d01c5dfSDouglas Gilbert 						dp->uas_bm);
45710d01c5dfSDouglas Gilbert 				}
45720d01c5dfSDouglas Gilbert 			}
45734bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
45740d01c5dfSDouglas Gilbert 		}
4575c65b1445SDouglas Gilbert 		return count;
4576c65b1445SDouglas Gilbert 	}
4577c65b1445SDouglas Gilbert 	return -EINVAL;
4578c65b1445SDouglas Gilbert }
457982069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
4580c65b1445SDouglas Gilbert 
458182069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
45821da177e4SLinus Torvalds {
45831da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
45841da177e4SLinus Torvalds }
45851da177e4SLinus Torvalds 
458682069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
458782069379SAkinobu Mita 			      size_t count)
45881da177e4SLinus Torvalds {
45891da177e4SLinus Torvalds 	int delta_hosts;
45901da177e4SLinus Torvalds 
4591f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
45921da177e4SLinus Torvalds 		return -EINVAL;
45931da177e4SLinus Torvalds 	if (delta_hosts > 0) {
45941da177e4SLinus Torvalds 		do {
45951da177e4SLinus Torvalds 			sdebug_add_adapter();
45961da177e4SLinus Torvalds 		} while (--delta_hosts);
45971da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
45981da177e4SLinus Torvalds 		do {
45991da177e4SLinus Torvalds 			sdebug_remove_adapter();
46001da177e4SLinus Torvalds 		} while (++delta_hosts);
46011da177e4SLinus Torvalds 	}
46021da177e4SLinus Torvalds 	return count;
46031da177e4SLinus Torvalds }
460482069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
46051da177e4SLinus Torvalds 
460682069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
460723183910SDouglas Gilbert {
460823183910SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
460923183910SDouglas Gilbert }
461082069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
461182069379SAkinobu Mita 				    size_t count)
461223183910SDouglas Gilbert {
461323183910SDouglas Gilbert 	int n;
461423183910SDouglas Gilbert 
461523183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
461623183910SDouglas Gilbert 		scsi_debug_vpd_use_hostno = n;
461723183910SDouglas Gilbert 		return count;
461823183910SDouglas Gilbert 	}
461923183910SDouglas Gilbert 	return -EINVAL;
462023183910SDouglas Gilbert }
462182069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
462223183910SDouglas Gilbert 
462382069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
4624597136abSMartin K. Petersen {
4625597136abSMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
4626597136abSMartin K. Petersen }
462782069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
4628597136abSMartin K. Petersen 
462982069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
4630c6a44287SMartin K. Petersen {
4631c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
4632c6a44287SMartin K. Petersen }
463382069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
4634c6a44287SMartin K. Petersen 
463582069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
4636c6a44287SMartin K. Petersen {
4637c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
4638c6a44287SMartin K. Petersen }
463982069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
4640c6a44287SMartin K. Petersen 
464182069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
4642c6a44287SMartin K. Petersen {
464368aee7baSAkinobu Mita 	return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_guard);
4644c6a44287SMartin K. Petersen }
464582069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
4646c6a44287SMartin K. Petersen 
464782069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
4648c6a44287SMartin K. Petersen {
4649c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
4650c6a44287SMartin K. Petersen }
465182069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
4652c6a44287SMartin K. Petersen 
465382069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
465444d92694SMartin K. Petersen {
465544d92694SMartin K. Petersen 	ssize_t count;
465644d92694SMartin K. Petersen 
46575b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
465844d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
465944d92694SMartin K. Petersen 				 sdebug_store_sectors);
466044d92694SMartin K. Petersen 
4661c7badc90STejun Heo 	count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
4662c7badc90STejun Heo 			  (int)map_size, map_storep);
466344d92694SMartin K. Petersen 	buf[count++] = '\n';
4664c7badc90STejun Heo 	buf[count] = '\0';
466544d92694SMartin K. Petersen 
466644d92694SMartin K. Petersen 	return count;
466744d92694SMartin K. Petersen }
466882069379SAkinobu Mita static DRIVER_ATTR_RO(map);
466944d92694SMartin K. Petersen 
467082069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
4671d986788bSMartin Pitt {
4672d986788bSMartin Pitt 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_removable ? 1 : 0);
4673d986788bSMartin Pitt }
467482069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
467582069379SAkinobu Mita 			       size_t count)
4676d986788bSMartin Pitt {
4677d986788bSMartin Pitt 	int n;
4678d986788bSMartin Pitt 
4679d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4680d986788bSMartin Pitt 		scsi_debug_removable = (n > 0);
4681d986788bSMartin Pitt 		return count;
4682d986788bSMartin Pitt 	}
4683d986788bSMartin Pitt 	return -EINVAL;
4684d986788bSMartin Pitt }
468582069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
4686d986788bSMartin Pitt 
4687cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4688cbf67842SDouglas Gilbert {
4689cbf67842SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!scsi_debug_host_lock);
4690cbf67842SDouglas Gilbert }
4691cbf67842SDouglas Gilbert /* Returns -EBUSY if host_lock is being changed and commands are queued */
4692cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4693cbf67842SDouglas Gilbert 			       size_t count)
4694cbf67842SDouglas Gilbert {
4695cbf67842SDouglas Gilbert 	int n, res;
4696cbf67842SDouglas Gilbert 
4697cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4698cbf67842SDouglas Gilbert 		bool new_host_lock = (n > 0);
4699cbf67842SDouglas Gilbert 
4700cbf67842SDouglas Gilbert 		res = count;
4701cbf67842SDouglas Gilbert 		if (new_host_lock != scsi_debug_host_lock) {
4702cbf67842SDouglas Gilbert 			unsigned long iflags;
4703cbf67842SDouglas Gilbert 			int k;
4704cbf67842SDouglas Gilbert 
4705cbf67842SDouglas Gilbert 			spin_lock_irqsave(&queued_arr_lock, iflags);
4706cbf67842SDouglas Gilbert 			k = find_first_bit(queued_in_use_bm,
4707cbf67842SDouglas Gilbert 					   scsi_debug_max_queue);
4708cbf67842SDouglas Gilbert 			if (k != scsi_debug_max_queue)
4709cbf67842SDouglas Gilbert 				res = -EBUSY;	/* have queued commands */
4710cbf67842SDouglas Gilbert 			else
4711cbf67842SDouglas Gilbert 				scsi_debug_host_lock = new_host_lock;
4712cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
4713cbf67842SDouglas Gilbert 		}
4714cbf67842SDouglas Gilbert 		return res;
4715cbf67842SDouglas Gilbert 	}
4716cbf67842SDouglas Gilbert 	return -EINVAL;
4717cbf67842SDouglas Gilbert }
4718cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
4719cbf67842SDouglas Gilbert 
4720c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
4721c2248fc9SDouglas Gilbert {
4722c2248fc9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!scsi_debug_strict);
4723c2248fc9SDouglas Gilbert }
4724c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4725c2248fc9SDouglas Gilbert 			    size_t count)
4726c2248fc9SDouglas Gilbert {
4727c2248fc9SDouglas Gilbert 	int n;
4728c2248fc9SDouglas Gilbert 
4729c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4730c2248fc9SDouglas Gilbert 		scsi_debug_strict = (n > 0);
4731c2248fc9SDouglas Gilbert 		return count;
4732c2248fc9SDouglas Gilbert 	}
4733c2248fc9SDouglas Gilbert 	return -EINVAL;
4734c2248fc9SDouglas Gilbert }
4735c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
4736c2248fc9SDouglas Gilbert 
4737cbf67842SDouglas Gilbert 
473882069379SAkinobu Mita /* Note: The following array creates attribute files in the
473923183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
474023183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
474123183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
474223183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
474323183910SDouglas Gilbert  */
47446ecaff7fSRandy Dunlap 
474582069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
474682069379SAkinobu Mita 	&driver_attr_delay.attr,
474782069379SAkinobu Mita 	&driver_attr_opts.attr,
474882069379SAkinobu Mita 	&driver_attr_ptype.attr,
474982069379SAkinobu Mita 	&driver_attr_dsense.attr,
475082069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
475182069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
475282069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
475382069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
475482069379SAkinobu Mita 	&driver_attr_num_parts.attr,
475582069379SAkinobu Mita 	&driver_attr_every_nth.attr,
475682069379SAkinobu Mita 	&driver_attr_max_luns.attr,
475782069379SAkinobu Mita 	&driver_attr_max_queue.attr,
475882069379SAkinobu Mita 	&driver_attr_no_uld.attr,
475982069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
476082069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
476182069379SAkinobu Mita 	&driver_attr_add_host.attr,
476282069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
476382069379SAkinobu Mita 	&driver_attr_sector_size.attr,
476482069379SAkinobu Mita 	&driver_attr_dix.attr,
476582069379SAkinobu Mita 	&driver_attr_dif.attr,
476682069379SAkinobu Mita 	&driver_attr_guard.attr,
476782069379SAkinobu Mita 	&driver_attr_ato.attr,
476882069379SAkinobu Mita 	&driver_attr_map.attr,
476982069379SAkinobu Mita 	&driver_attr_removable.attr,
4770cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
4771cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
4772c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
477382069379SAkinobu Mita 	NULL,
477482069379SAkinobu Mita };
477582069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
47761da177e4SLinus Torvalds 
477711ddcecaSAkinobu Mita static struct device *pseudo_primary;
47788dea0d02SFUJITA Tomonori 
47791da177e4SLinus Torvalds static int __init scsi_debug_init(void)
47801da177e4SLinus Torvalds {
47815f2578e5SFUJITA Tomonori 	unsigned long sz;
47821da177e4SLinus Torvalds 	int host_to_add;
47831da177e4SLinus Torvalds 	int k;
47846ecaff7fSRandy Dunlap 	int ret;
47851da177e4SLinus Torvalds 
4786cbf67842SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
4787cbf67842SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
4788cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
4789cbf67842SDouglas Gilbert 
4790cbf67842SDouglas Gilbert 	if (scsi_debug_ndelay >= 1000000000) {
4791c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
4792cbf67842SDouglas Gilbert 		scsi_debug_ndelay = 0;
4793cbf67842SDouglas Gilbert 	} else if (scsi_debug_ndelay > 0)
4794cbf67842SDouglas Gilbert 		scsi_debug_delay = DELAY_OVERRIDDEN;
4795cbf67842SDouglas Gilbert 
4796597136abSMartin K. Petersen 	switch (scsi_debug_sector_size) {
4797597136abSMartin K. Petersen 	case  512:
4798597136abSMartin K. Petersen 	case 1024:
4799597136abSMartin K. Petersen 	case 2048:
4800597136abSMartin K. Petersen 	case 4096:
4801597136abSMartin K. Petersen 		break;
4802597136abSMartin K. Petersen 	default:
4803c1287970STomas Winkler 		pr_err("invalid sector_size %d\n", scsi_debug_sector_size);
4804597136abSMartin K. Petersen 		return -EINVAL;
4805597136abSMartin K. Petersen 	}
4806597136abSMartin K. Petersen 
4807c6a44287SMartin K. Petersen 	switch (scsi_debug_dif) {
4808c6a44287SMartin K. Petersen 
4809c6a44287SMartin K. Petersen 	case SD_DIF_TYPE0_PROTECTION:
4810c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
4811395cef03SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
4812c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
4813c6a44287SMartin K. Petersen 		break;
4814c6a44287SMartin K. Petersen 
4815c6a44287SMartin K. Petersen 	default:
4816c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
4817c6a44287SMartin K. Petersen 		return -EINVAL;
4818c6a44287SMartin K. Petersen 	}
4819c6a44287SMartin K. Petersen 
4820c6a44287SMartin K. Petersen 	if (scsi_debug_guard > 1) {
4821c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
4822c6a44287SMartin K. Petersen 		return -EINVAL;
4823c6a44287SMartin K. Petersen 	}
4824c6a44287SMartin K. Petersen 
4825c6a44287SMartin K. Petersen 	if (scsi_debug_ato > 1) {
4826c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
4827c6a44287SMartin K. Petersen 		return -EINVAL;
4828c6a44287SMartin K. Petersen 	}
4829c6a44287SMartin K. Petersen 
4830ea61fca5SMartin K. Petersen 	if (scsi_debug_physblk_exp > 15) {
4831c1287970STomas Winkler 		pr_err("invalid physblk_exp %u\n", scsi_debug_physblk_exp);
4832ea61fca5SMartin K. Petersen 		return -EINVAL;
4833ea61fca5SMartin K. Petersen 	}
4834ea61fca5SMartin K. Petersen 
4835ea61fca5SMartin K. Petersen 	if (scsi_debug_lowest_aligned > 0x3fff) {
4836c1287970STomas Winkler 		pr_err("lowest_aligned too big: %u\n",
4837ea61fca5SMartin K. Petersen 			scsi_debug_lowest_aligned);
4838ea61fca5SMartin K. Petersen 		return -EINVAL;
4839ea61fca5SMartin K. Petersen 	}
4840ea61fca5SMartin K. Petersen 
48411da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb < 1)
48421da177e4SLinus Torvalds 		scsi_debug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
48435f2578e5SFUJITA Tomonori 	sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
4844597136abSMartin K. Petersen 	sdebug_store_sectors = sz / scsi_debug_sector_size;
484528898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
48461da177e4SLinus Torvalds 
48471da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
48481da177e4SLinus Torvalds 	sdebug_heads = 8;
48491da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
4850fa785f0aSAndy Shevchenko 	if (scsi_debug_dev_size_mb >= 256)
48511da177e4SLinus Torvalds 		sdebug_heads = 64;
4852fa785f0aSAndy Shevchenko 	else if (scsi_debug_dev_size_mb >= 16)
4853fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
48541da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
48551da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
48561da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
48571da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
48581da177e4SLinus Torvalds 		sdebug_heads = 255;
48591da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
48601da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
48611da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
48621da177e4SLinus Torvalds 	}
48631da177e4SLinus Torvalds 
4864cbf67842SDouglas Gilbert 	if (0 == scsi_debug_fake_rw) {
48651da177e4SLinus Torvalds 		fake_storep = vmalloc(sz);
48661da177e4SLinus Torvalds 		if (NULL == fake_storep) {
4867c1287970STomas Winkler 			pr_err("out of memory, 1\n");
48681da177e4SLinus Torvalds 			return -ENOMEM;
48691da177e4SLinus Torvalds 		}
48701da177e4SLinus Torvalds 		memset(fake_storep, 0, sz);
48711da177e4SLinus Torvalds 		if (scsi_debug_num_parts > 0)
4872f58b0efbSFUJITA Tomonori 			sdebug_build_parts(fake_storep, sz);
4873cbf67842SDouglas Gilbert 	}
48741da177e4SLinus Torvalds 
48757cb69d03SAkinobu Mita 	if (scsi_debug_dix) {
4876c6a44287SMartin K. Petersen 		int dif_size;
4877c6a44287SMartin K. Petersen 
4878c6a44287SMartin K. Petersen 		dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
4879c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
4880c6a44287SMartin K. Petersen 
4881c1287970STomas Winkler 		pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
4882c6a44287SMartin K. Petersen 
4883c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
4884c1287970STomas Winkler 			pr_err("out of mem. (DIX)\n");
4885c6a44287SMartin K. Petersen 			ret = -ENOMEM;
4886c6a44287SMartin K. Petersen 			goto free_vm;
4887c6a44287SMartin K. Petersen 		}
4888c6a44287SMartin K. Petersen 
4889c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
4890c6a44287SMartin K. Petersen 	}
4891c6a44287SMartin K. Petersen 
48925b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
48935b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
48946014759cSMartin K. Petersen 		scsi_debug_unmap_max_blocks =
48956014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU);
48966014759cSMartin K. Petersen 
48976014759cSMartin K. Petersen 		scsi_debug_unmap_max_desc =
48986014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_max_desc, 0U, 256U);
48996014759cSMartin K. Petersen 
49006014759cSMartin K. Petersen 		scsi_debug_unmap_granularity =
49016014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU);
49026014759cSMartin K. Petersen 
49036014759cSMartin K. Petersen 		if (scsi_debug_unmap_alignment &&
4904ac17078aSAkinobu Mita 		    scsi_debug_unmap_granularity <=
4905ac17078aSAkinobu Mita 		    scsi_debug_unmap_alignment) {
4906c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
490744d92694SMartin K. Petersen 			return -EINVAL;
490844d92694SMartin K. Petersen 		}
490944d92694SMartin K. Petersen 
4910b90ebc3dSAkinobu Mita 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
4911b90ebc3dSAkinobu Mita 		map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
491244d92694SMartin K. Petersen 
4913c1287970STomas Winkler 		pr_info("%lu provisioning blocks\n", map_size);
491444d92694SMartin K. Petersen 
491544d92694SMartin K. Petersen 		if (map_storep == NULL) {
4916c1287970STomas Winkler 			pr_err("out of mem. (MAP)\n");
491744d92694SMartin K. Petersen 			ret = -ENOMEM;
491844d92694SMartin K. Petersen 			goto free_vm;
491944d92694SMartin K. Petersen 		}
492044d92694SMartin K. Petersen 
4921b90ebc3dSAkinobu Mita 		bitmap_zero(map_storep, map_size);
492244d92694SMartin K. Petersen 
492344d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
492444d92694SMartin K. Petersen 		if (scsi_debug_num_parts)
492544d92694SMartin K. Petersen 			map_region(0, 2);
492644d92694SMartin K. Petersen 	}
492744d92694SMartin K. Petersen 
49289b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
49299b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
4930c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
49319b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
49326ecaff7fSRandy Dunlap 		goto free_vm;
49336ecaff7fSRandy Dunlap 	}
49346ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
49356ecaff7fSRandy Dunlap 	if (ret < 0) {
4936c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
49376ecaff7fSRandy Dunlap 		goto dev_unreg;
49386ecaff7fSRandy Dunlap 	}
49396ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
49406ecaff7fSRandy Dunlap 	if (ret < 0) {
4941c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
49426ecaff7fSRandy Dunlap 		goto bus_unreg;
49436ecaff7fSRandy Dunlap 	}
49441da177e4SLinus Torvalds 
49451da177e4SLinus Torvalds 	host_to_add = scsi_debug_add_host;
49461da177e4SLinus Torvalds         scsi_debug_add_host = 0;
49471da177e4SLinus Torvalds 
49481da177e4SLinus Torvalds         for (k = 0; k < host_to_add; k++) {
49491da177e4SLinus Torvalds                 if (sdebug_add_adapter()) {
4950c1287970STomas Winkler 			pr_err("sdebug_add_adapter failed k=%d\n", k);
49511da177e4SLinus Torvalds                         break;
49521da177e4SLinus Torvalds                 }
49531da177e4SLinus Torvalds         }
49541da177e4SLinus Torvalds 
4955c1287970STomas Winkler 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
4956c1287970STomas Winkler 		pr_info("built %d host(s)\n", scsi_debug_add_host);
4957c1287970STomas Winkler 
49581da177e4SLinus Torvalds 	return 0;
49596ecaff7fSRandy Dunlap 
49606ecaff7fSRandy Dunlap bus_unreg:
49616ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
49626ecaff7fSRandy Dunlap dev_unreg:
49639b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
49646ecaff7fSRandy Dunlap free_vm:
496544d92694SMartin K. Petersen 	vfree(map_storep);
4966c6a44287SMartin K. Petersen 	vfree(dif_storep);
49676ecaff7fSRandy Dunlap 	vfree(fake_storep);
49686ecaff7fSRandy Dunlap 
49696ecaff7fSRandy Dunlap 	return ret;
49701da177e4SLinus Torvalds }
49711da177e4SLinus Torvalds 
49721da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
49731da177e4SLinus Torvalds {
49741da177e4SLinus Torvalds 	int k = scsi_debug_add_host;
49751da177e4SLinus Torvalds 
49761da177e4SLinus Torvalds 	stop_all_queued();
4977cbf67842SDouglas Gilbert 	free_all_queued();
49781da177e4SLinus Torvalds 	for (; k; k--)
49791da177e4SLinus Torvalds 		sdebug_remove_adapter();
49801da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
49811da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
49829b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
49831da177e4SLinus Torvalds 
4984c6a44287SMartin K. Petersen 	vfree(dif_storep);
49851da177e4SLinus Torvalds 	vfree(fake_storep);
49861da177e4SLinus Torvalds }
49871da177e4SLinus Torvalds 
49881da177e4SLinus Torvalds device_initcall(scsi_debug_init);
49891da177e4SLinus Torvalds module_exit(scsi_debug_exit);
49901da177e4SLinus Torvalds 
49911da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev)
49921da177e4SLinus Torvalds {
49931da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
49941da177e4SLinus Torvalds 
49951da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
49961da177e4SLinus Torvalds         kfree(sdbg_host);
49971da177e4SLinus Torvalds }
49981da177e4SLinus Torvalds 
49991da177e4SLinus Torvalds static int sdebug_add_adapter(void)
50001da177e4SLinus Torvalds {
50011da177e4SLinus Torvalds 	int k, devs_per_host;
50021da177e4SLinus Torvalds         int error = 0;
50031da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
50048b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
50051da177e4SLinus Torvalds 
500624669f75SJes Sorensen         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
50071da177e4SLinus Torvalds         if (NULL == sdbg_host) {
5008c1287970STomas Winkler 		pr_err("out of memory at line %d\n", __LINE__);
50091da177e4SLinus Torvalds                 return -ENOMEM;
50101da177e4SLinus Torvalds         }
50111da177e4SLinus Torvalds 
50121da177e4SLinus Torvalds         INIT_LIST_HEAD(&sdbg_host->dev_info_list);
50131da177e4SLinus Torvalds 
50141da177e4SLinus Torvalds 	devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
50151da177e4SLinus Torvalds         for (k = 0; k < devs_per_host; k++) {
50165cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
50175cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
5018c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
50191da177e4SLinus Torvalds                         error = -ENOMEM;
50201da177e4SLinus Torvalds 			goto clean;
50211da177e4SLinus Torvalds                 }
50221da177e4SLinus Torvalds         }
50231da177e4SLinus Torvalds 
50241da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
50251da177e4SLinus Torvalds         list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
50261da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
50271da177e4SLinus Torvalds 
50281da177e4SLinus Torvalds         sdbg_host->dev.bus = &pseudo_lld_bus;
50299b906779SNicholas Bellinger         sdbg_host->dev.parent = pseudo_primary;
50301da177e4SLinus Torvalds         sdbg_host->dev.release = &sdebug_release_adapter;
503171610f55SKay Sievers         dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
50321da177e4SLinus Torvalds 
50331da177e4SLinus Torvalds         error = device_register(&sdbg_host->dev);
50341da177e4SLinus Torvalds 
50351da177e4SLinus Torvalds         if (error)
50361da177e4SLinus Torvalds 		goto clean;
50371da177e4SLinus Torvalds 
50381da177e4SLinus Torvalds 	++scsi_debug_add_host;
50391da177e4SLinus Torvalds         return error;
50401da177e4SLinus Torvalds 
50411da177e4SLinus Torvalds clean:
50428b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
50438b40228fSFUJITA Tomonori 				 dev_list) {
50441da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
50451da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
50461da177e4SLinus Torvalds 	}
50471da177e4SLinus Torvalds 
50481da177e4SLinus Torvalds 	kfree(sdbg_host);
50491da177e4SLinus Torvalds         return error;
50501da177e4SLinus Torvalds }
50511da177e4SLinus Torvalds 
50521da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
50531da177e4SLinus Torvalds {
50541da177e4SLinus Torvalds         struct sdebug_host_info * sdbg_host = NULL;
50551da177e4SLinus Torvalds 
50561da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
50571da177e4SLinus Torvalds         if (!list_empty(&sdebug_host_list)) {
50581da177e4SLinus Torvalds                 sdbg_host = list_entry(sdebug_host_list.prev,
50591da177e4SLinus Torvalds                                        struct sdebug_host_info, host_list);
50601da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
50611da177e4SLinus Torvalds 	}
50621da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
50631da177e4SLinus Torvalds 
50641da177e4SLinus Torvalds 	if (!sdbg_host)
50651da177e4SLinus Torvalds 		return;
50661da177e4SLinus Torvalds 
50671da177e4SLinus Torvalds         device_unregister(&sdbg_host->dev);
50681da177e4SLinus Torvalds         --scsi_debug_add_host;
50691da177e4SLinus Torvalds }
50701da177e4SLinus Torvalds 
5071cbf67842SDouglas Gilbert static int
5072db5ed4dfSChristoph Hellwig sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
5073cbf67842SDouglas Gilbert {
5074cbf67842SDouglas Gilbert 	int num_in_q = 0;
5075cbf67842SDouglas Gilbert 	unsigned long iflags;
5076cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
5077cbf67842SDouglas Gilbert 
5078cbf67842SDouglas Gilbert 	spin_lock_irqsave(&queued_arr_lock, iflags);
5079cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
5080cbf67842SDouglas Gilbert 	if (NULL == devip) {
5081cbf67842SDouglas Gilbert 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
5082cbf67842SDouglas Gilbert 		return	-ENODEV;
5083cbf67842SDouglas Gilbert 	}
5084cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
5085cbf67842SDouglas Gilbert 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
5086c40ecc12SChristoph Hellwig 
5087cbf67842SDouglas Gilbert 	if (qdepth < 1)
5088cbf67842SDouglas Gilbert 		qdepth = 1;
5089cbf67842SDouglas Gilbert 	/* allow to exceed max host queued_arr elements for testing */
5090cbf67842SDouglas Gilbert 	if (qdepth > SCSI_DEBUG_CANQUEUE + 10)
5091cbf67842SDouglas Gilbert 		qdepth = SCSI_DEBUG_CANQUEUE + 10;
5092db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
5093cbf67842SDouglas Gilbert 
5094c40ecc12SChristoph Hellwig 	if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) {
5095cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev,
5096c40ecc12SChristoph Hellwig 			    "%s: qdepth=%d, num_in_q=%d\n",
5097c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
5098cbf67842SDouglas Gilbert 	}
5099cbf67842SDouglas Gilbert 	return sdev->queue_depth;
5100cbf67842SDouglas Gilbert }
5101cbf67842SDouglas Gilbert 
5102cbf67842SDouglas Gilbert static int
5103817fd66bSDouglas Gilbert check_inject(struct scsi_cmnd *scp)
5104817fd66bSDouglas Gilbert {
5105817fd66bSDouglas Gilbert 	struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
5106817fd66bSDouglas Gilbert 
5107817fd66bSDouglas Gilbert 	memset(ep, 0, sizeof(struct sdebug_scmd_extra_t));
5108817fd66bSDouglas Gilbert 
5109817fd66bSDouglas Gilbert 	if (atomic_inc_return(&sdebug_cmnd_count) >=
5110817fd66bSDouglas Gilbert 	    abs(scsi_debug_every_nth)) {
5111817fd66bSDouglas Gilbert 		atomic_set(&sdebug_cmnd_count, 0);
5112817fd66bSDouglas Gilbert 		if (scsi_debug_every_nth < -1)
5113817fd66bSDouglas Gilbert 			scsi_debug_every_nth = -1;
5114817fd66bSDouglas Gilbert 		if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
5115817fd66bSDouglas Gilbert 			return 1; /* ignore command causing timeout */
5116817fd66bSDouglas Gilbert 		else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts &&
5117817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
5118817fd66bSDouglas Gilbert 			return 1; /* time out reads and writes */
5119817fd66bSDouglas Gilbert 		if (sdebug_any_injecting_opt) {
5120817fd66bSDouglas Gilbert 			int opts = scsi_debug_opts;
5121817fd66bSDouglas Gilbert 
5122817fd66bSDouglas Gilbert 			if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts)
5123817fd66bSDouglas Gilbert 				ep->inj_recovered = true;
5124817fd66bSDouglas Gilbert 			else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts)
5125817fd66bSDouglas Gilbert 				ep->inj_transport = true;
5126817fd66bSDouglas Gilbert 			else if (SCSI_DEBUG_OPT_DIF_ERR & opts)
5127817fd66bSDouglas Gilbert 				ep->inj_dif = true;
5128817fd66bSDouglas Gilbert 			else if (SCSI_DEBUG_OPT_DIX_ERR & opts)
5129817fd66bSDouglas Gilbert 				ep->inj_dix = true;
5130817fd66bSDouglas Gilbert 			else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts)
5131817fd66bSDouglas Gilbert 				ep->inj_short = true;
5132817fd66bSDouglas Gilbert 		}
5133817fd66bSDouglas Gilbert 	}
5134817fd66bSDouglas Gilbert 	return 0;
5135817fd66bSDouglas Gilbert }
5136817fd66bSDouglas Gilbert 
5137c2248fc9SDouglas Gilbert static int
5138c2248fc9SDouglas Gilbert scsi_debug_queuecommand(struct scsi_cmnd *scp)
5139c2248fc9SDouglas Gilbert {
5140c2248fc9SDouglas Gilbert 	u8 sdeb_i;
5141c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
5142c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
5143c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
5144c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
5145c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
5146c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5147c2248fc9SDouglas Gilbert 	int k, na;
5148c2248fc9SDouglas Gilbert 	int errsts = 0;
5149c2248fc9SDouglas Gilbert 	int errsts_no_connect = DID_NO_CONNECT << 16;
5150c2248fc9SDouglas Gilbert 	u32 flags;
5151c2248fc9SDouglas Gilbert 	u16 sa;
5152c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
5153c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
5154c2248fc9SDouglas Gilbert 	bool debug = !!(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts);
5155c2248fc9SDouglas Gilbert 
5156c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
5157c2248fc9SDouglas Gilbert 	if (debug && !(SCSI_DEBUG_OPT_NO_CDB_NOISE & scsi_debug_opts)) {
5158c2248fc9SDouglas Gilbert 		char b[120];
5159c2248fc9SDouglas Gilbert 		int n, len, sb;
5160c2248fc9SDouglas Gilbert 
5161c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
5162c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
5163c2248fc9SDouglas Gilbert 		if (len > 32)
5164c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
5165c2248fc9SDouglas Gilbert 		else {
5166c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
5167c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
5168c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
5169c2248fc9SDouglas Gilbert 		}
5170c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, b);
5171c2248fc9SDouglas Gilbert 	}
517234d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
5173c2248fc9SDouglas Gilbert 	if ((sdp->lun >= scsi_debug_max_luns) && !has_wlun_rl)
5174c2248fc9SDouglas Gilbert 		return schedule_resp(scp, NULL, errsts_no_connect, 0);
5175c2248fc9SDouglas Gilbert 
5176c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
5177c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
5178c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
5179c2248fc9SDouglas Gilbert 	if (!devip) {
5180c2248fc9SDouglas Gilbert 		devip = devInfoReg(sdp);
5181c2248fc9SDouglas Gilbert 		if (NULL == devip)
5182c2248fc9SDouglas Gilbert 			return schedule_resp(scp, NULL, errsts_no_connect, 0);
5183c2248fc9SDouglas Gilbert 	}
5184c2248fc9SDouglas Gilbert 	na = oip->num_attached;
5185c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
5186c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
5187c2248fc9SDouglas Gilbert 		r_oip = oip;
5188c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
5189c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
5190c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
5191c2248fc9SDouglas Gilbert 			else
5192c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
5193c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5194c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
5195c2248fc9SDouglas Gilbert 					break;
5196c2248fc9SDouglas Gilbert 			}
5197c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
5198c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5199c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
5200c2248fc9SDouglas Gilbert 					break;
5201c2248fc9SDouglas Gilbert 			}
5202c2248fc9SDouglas Gilbert 		}
5203c2248fc9SDouglas Gilbert 		if (k > na) {
5204c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
5205c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5206c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
5207c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5208c2248fc9SDouglas Gilbert 			else
5209c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
5210c2248fc9SDouglas Gilbert 			goto check_cond;
5211c2248fc9SDouglas Gilbert 		}
5212c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
5213c2248fc9SDouglas Gilbert 	flags = oip->flags;
5214c2248fc9SDouglas Gilbert 	if (F_INV_OP & flags) {
5215c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5216c2248fc9SDouglas Gilbert 		goto check_cond;
5217c2248fc9SDouglas Gilbert 	}
5218c2248fc9SDouglas Gilbert 	if (has_wlun_rl && !(F_RL_WLUN_OK & flags)) {
5219c2248fc9SDouglas Gilbert 		if (debug)
5220c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "scsi_debug: Opcode: "
5221c2248fc9SDouglas Gilbert 				    "0x%x not supported for wlun\n", opcode);
5222c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5223c2248fc9SDouglas Gilbert 		goto check_cond;
5224c2248fc9SDouglas Gilbert 	}
5225c2248fc9SDouglas Gilbert 	if (scsi_debug_strict) {	/* check cdb against mask */
5226c2248fc9SDouglas Gilbert 		u8 rem;
5227c2248fc9SDouglas Gilbert 		int j;
5228c2248fc9SDouglas Gilbert 
5229c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5230c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
5231c2248fc9SDouglas Gilbert 			if (rem) {
5232c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
5233c2248fc9SDouglas Gilbert 					if (0x80 & rem)
5234c2248fc9SDouglas Gilbert 						break;
5235c2248fc9SDouglas Gilbert 				}
5236c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5237c2248fc9SDouglas Gilbert 				goto check_cond;
5238c2248fc9SDouglas Gilbert 			}
5239c2248fc9SDouglas Gilbert 		}
5240c2248fc9SDouglas Gilbert 	}
5241c2248fc9SDouglas Gilbert 	if (!(F_SKIP_UA & flags) &&
5242c2248fc9SDouglas Gilbert 	    SDEBUG_NUM_UAS != find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS)) {
5243c2248fc9SDouglas Gilbert 		errsts = check_readiness(scp, UAS_ONLY, devip);
5244c2248fc9SDouglas Gilbert 		if (errsts)
5245c2248fc9SDouglas Gilbert 			goto check_cond;
5246c2248fc9SDouglas Gilbert 	}
5247c2248fc9SDouglas Gilbert 	if ((F_M_ACCESS & flags) && devip->stopped) {
5248c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
5249c2248fc9SDouglas Gilbert 		if (debug)
5250c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5251c2248fc9SDouglas Gilbert 				    "%s\n", my_name, "initializing command "
5252c2248fc9SDouglas Gilbert 				    "required");
5253c2248fc9SDouglas Gilbert 		errsts = check_condition_result;
5254c2248fc9SDouglas Gilbert 		goto fini;
5255c2248fc9SDouglas Gilbert 	}
5256c2248fc9SDouglas Gilbert 	if (scsi_debug_fake_rw && (F_FAKE_RW & flags))
5257c2248fc9SDouglas Gilbert 		goto fini;
5258c2248fc9SDouglas Gilbert 	if (scsi_debug_every_nth) {
5259c2248fc9SDouglas Gilbert 		if (check_inject(scp))
5260c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
5261c2248fc9SDouglas Gilbert 	}
5262c2248fc9SDouglas Gilbert 	if (oip->pfp)	/* if this command has a resp_* function, call it */
5263c2248fc9SDouglas Gilbert 		errsts = oip->pfp(scp, devip);
5264c2248fc9SDouglas Gilbert 	else if (r_pfp)	/* if leaf function ptr NULL, try the root's */
5265c2248fc9SDouglas Gilbert 		errsts = r_pfp(scp, devip);
5266c2248fc9SDouglas Gilbert 
5267c2248fc9SDouglas Gilbert fini:
5268c2248fc9SDouglas Gilbert 	return schedule_resp(scp, devip, errsts,
5269c2248fc9SDouglas Gilbert 			     ((F_DELAY_OVERR & flags) ? 0 : scsi_debug_delay));
5270c2248fc9SDouglas Gilbert check_cond:
5271c2248fc9SDouglas Gilbert 	return schedule_resp(scp, devip, check_condition_result, 0);
5272c2248fc9SDouglas Gilbert }
5273c2248fc9SDouglas Gilbert 
527438d5c833SDouglas Gilbert static int
527538d5c833SDouglas Gilbert sdebug_queuecommand_lock_or_not(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
527638d5c833SDouglas Gilbert {
527738d5c833SDouglas Gilbert 	if (scsi_debug_host_lock) {
527838d5c833SDouglas Gilbert 		unsigned long iflags;
527938d5c833SDouglas Gilbert 		int rc;
528038d5c833SDouglas Gilbert 
528138d5c833SDouglas Gilbert 		spin_lock_irqsave(shost->host_lock, iflags);
528238d5c833SDouglas Gilbert 		rc = scsi_debug_queuecommand(cmd);
528338d5c833SDouglas Gilbert 		spin_unlock_irqrestore(shost->host_lock, iflags);
528438d5c833SDouglas Gilbert 		return rc;
528538d5c833SDouglas Gilbert 	} else
528638d5c833SDouglas Gilbert 		return scsi_debug_queuecommand(cmd);
528738d5c833SDouglas Gilbert }
528838d5c833SDouglas Gilbert 
52899e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
5290c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
5291c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
52929e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
52939e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
52949e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
52959e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
52969e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
52979e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
52989e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
5299cbf67842SDouglas Gilbert 	.queuecommand =		sdebug_queuecommand_lock_or_not,
5300cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
53019e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
53029e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
5303cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
5304cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
53059e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
53069e603ca0SFUJITA Tomonori 	.can_queue =		SCSI_DEBUG_CANQUEUE,
53079e603ca0SFUJITA Tomonori 	.this_id =		7,
530865e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
5309cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
53106bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
53119e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
53129e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
5313c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
5314817fd66bSDouglas Gilbert 	.cmd_size =		sizeof(struct sdebug_scmd_extra_t),
53159e603ca0SFUJITA Tomonori };
53169e603ca0SFUJITA Tomonori 
53171da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev)
53181da177e4SLinus Torvalds {
53191da177e4SLinus Torvalds 	int error = 0;
5320817fd66bSDouglas Gilbert 	int opts;
53211da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
53221da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
5323c6a44287SMartin K. Petersen 	int host_prot;
53241da177e4SLinus Torvalds 
53251da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
53261da177e4SLinus Torvalds 
532778d4e5a0SDouglas Gilbert 	sdebug_driver_template.can_queue = scsi_debug_max_queue;
53280759c666SAkinobu Mita 	if (scsi_debug_clustering)
53290759c666SAkinobu Mita 		sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
53301da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
53311da177e4SLinus Torvalds 	if (NULL == hpnt) {
5332c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
53331da177e4SLinus Torvalds 		error = -ENODEV;
53341da177e4SLinus Torvalds 		return error;
53351da177e4SLinus Torvalds 	}
53361da177e4SLinus Torvalds 
53371da177e4SLinus Torvalds         sdbg_host->shost = hpnt;
53381da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
53391da177e4SLinus Torvalds 	if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
53401da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts + 1;
53411da177e4SLinus Torvalds 	else
53421da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts;
5343f2d3fd29STomas Winkler 	/* = scsi_debug_max_luns; */
5344f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
53451da177e4SLinus Torvalds 
5346c6a44287SMartin K. Petersen 	host_prot = 0;
5347c6a44287SMartin K. Petersen 
5348c6a44287SMartin K. Petersen 	switch (scsi_debug_dif) {
5349c6a44287SMartin K. Petersen 
5350c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
5351c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE1_PROTECTION;
5352c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
5353c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE1_PROTECTION;
5354c6a44287SMartin K. Petersen 		break;
5355c6a44287SMartin K. Petersen 
5356c6a44287SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
5357c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE2_PROTECTION;
5358c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
5359c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE2_PROTECTION;
5360c6a44287SMartin K. Petersen 		break;
5361c6a44287SMartin K. Petersen 
5362c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
5363c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE3_PROTECTION;
5364c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
5365c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE3_PROTECTION;
5366c6a44287SMartin K. Petersen 		break;
5367c6a44287SMartin K. Petersen 
5368c6a44287SMartin K. Petersen 	default:
5369c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
5370c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE0_PROTECTION;
5371c6a44287SMartin K. Petersen 		break;
5372c6a44287SMartin K. Petersen 	}
5373c6a44287SMartin K. Petersen 
5374c6a44287SMartin K. Petersen 	scsi_host_set_prot(hpnt, host_prot);
5375c6a44287SMartin K. Petersen 
5376c1287970STomas Winkler 	pr_info("host protection%s%s%s%s%s%s%s\n",
5377c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5378c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5379c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5380c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5381c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5382c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5383c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
5384c6a44287SMartin K. Petersen 
5385c6a44287SMartin K. Petersen 	if (scsi_debug_guard == 1)
5386c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5387c6a44287SMartin K. Petersen 	else
5388c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5389c6a44287SMartin K. Petersen 
5390817fd66bSDouglas Gilbert 	opts = scsi_debug_opts;
5391817fd66bSDouglas Gilbert 	if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts)
5392817fd66bSDouglas Gilbert 		sdebug_any_injecting_opt = true;
5393817fd66bSDouglas Gilbert 	else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts)
5394817fd66bSDouglas Gilbert 		sdebug_any_injecting_opt = true;
5395817fd66bSDouglas Gilbert 	else if (SCSI_DEBUG_OPT_DIF_ERR & opts)
5396817fd66bSDouglas Gilbert 		sdebug_any_injecting_opt = true;
5397817fd66bSDouglas Gilbert 	else if (SCSI_DEBUG_OPT_DIX_ERR & opts)
5398817fd66bSDouglas Gilbert 		sdebug_any_injecting_opt = true;
5399817fd66bSDouglas Gilbert 	else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts)
5400817fd66bSDouglas Gilbert 		sdebug_any_injecting_opt = true;
5401817fd66bSDouglas Gilbert 
54021da177e4SLinus Torvalds         error = scsi_add_host(hpnt, &sdbg_host->dev);
54031da177e4SLinus Torvalds         if (error) {
5404c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
54051da177e4SLinus Torvalds                 error = -ENODEV;
54061da177e4SLinus Torvalds 		scsi_host_put(hpnt);
54071da177e4SLinus Torvalds         } else
54081da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
54091da177e4SLinus Torvalds 
54101da177e4SLinus Torvalds 	return error;
54111da177e4SLinus Torvalds }
54121da177e4SLinus Torvalds 
54131da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev)
54141da177e4SLinus Torvalds {
54151da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
54168b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
54171da177e4SLinus Torvalds 
54181da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
54191da177e4SLinus Torvalds 
54201da177e4SLinus Torvalds 	if (!sdbg_host) {
5421c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
54221da177e4SLinus Torvalds 		return -ENODEV;
54231da177e4SLinus Torvalds 	}
54241da177e4SLinus Torvalds 
54251da177e4SLinus Torvalds         scsi_remove_host(sdbg_host->shost);
54261da177e4SLinus Torvalds 
54278b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
54288b40228fSFUJITA Tomonori 				 dev_list) {
54291da177e4SLinus Torvalds                 list_del(&sdbg_devinfo->dev_list);
54301da177e4SLinus Torvalds                 kfree(sdbg_devinfo);
54311da177e4SLinus Torvalds         }
54321da177e4SLinus Torvalds 
54331da177e4SLinus Torvalds         scsi_host_put(sdbg_host->shost);
54341da177e4SLinus Torvalds         return 0;
54351da177e4SLinus Torvalds }
54361da177e4SLinus Torvalds 
54378dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
54388dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
54391da177e4SLinus Torvalds {
54408dea0d02SFUJITA Tomonori 	return 1;
54418dea0d02SFUJITA Tomonori }
54421da177e4SLinus Torvalds 
54438dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
54448dea0d02SFUJITA Tomonori 	.name = "pseudo",
54458dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
54468dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
54478dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
544882069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
54498dea0d02SFUJITA Tomonori };
5450