xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision d467d31f)
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 
281da177e4SLinus Torvalds #include <linux/module.h>
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds #include <linux/kernel.h>
311da177e4SLinus Torvalds #include <linux/errno.h>
321da177e4SLinus Torvalds #include <linux/timer.h>
335a0e3ad6STejun Heo #include <linux/slab.h>
341da177e4SLinus Torvalds #include <linux/types.h>
351da177e4SLinus Torvalds #include <linux/string.h>
361da177e4SLinus Torvalds #include <linux/genhd.h>
371da177e4SLinus Torvalds #include <linux/fs.h>
381da177e4SLinus Torvalds #include <linux/init.h>
391da177e4SLinus Torvalds #include <linux/proc_fs.h>
401da177e4SLinus Torvalds #include <linux/vmalloc.h>
411da177e4SLinus Torvalds #include <linux/moduleparam.h>
42852e034dSJens Axboe #include <linux/scatterlist.h>
431da177e4SLinus Torvalds #include <linux/blkdev.h>
44c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h>
45cbf67842SDouglas Gilbert #include <linux/spinlock.h>
46cbf67842SDouglas Gilbert #include <linux/interrupt.h>
47cbf67842SDouglas Gilbert #include <linux/atomic.h>
48cbf67842SDouglas Gilbert #include <linux/hrtimer.h>
49c6a44287SMartin K. Petersen 
50c6a44287SMartin K. Petersen #include <net/checksum.h>
519ff26eefSFUJITA Tomonori 
5244d92694SMartin K. Petersen #include <asm/unaligned.h>
5344d92694SMartin K. Petersen 
549ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
559ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
569ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
571da177e4SLinus Torvalds #include <scsi/scsi_host.h>
581da177e4SLinus Torvalds #include <scsi/scsicam.h>
59a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
60cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h>
61395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
621da177e4SLinus Torvalds 
63c6a44287SMartin K. Petersen #include "sd.h"
641da177e4SLinus Torvalds #include "scsi_logging.h"
651da177e4SLinus Torvalds 
6622017ed2SDouglas Gilbert #define SCSI_DEBUG_VERSION "1.85"
6722017ed2SDouglas Gilbert static const char *scsi_debug_version_date = "20141022";
68cbf67842SDouglas Gilbert 
69cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
701da177e4SLinus Torvalds 
716f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
72c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
73c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
74c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
751da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
76c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
771da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7822017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
791da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
80c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
81cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
82cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
8322017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8422017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
85cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
86cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
87cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
8822017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9
891da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
906f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
91c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
92c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
9322017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d
941da177e4SLinus Torvalds 
956f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
966f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
976f3cbf55SDouglas Gilbert 
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds /* Default values for driver parameters */
1001da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1011da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1021da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1031da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1041da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1051da177e4SLinus Torvalds  */
1065b94e232SMartin K. Petersen #define DEF_ATO 1
107cbf67842SDouglas Gilbert #define DEF_DELAY   1		/* if > 0 unit is a jiffy */
1081da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1095b94e232SMartin K. Petersen #define DEF_DIF 0
1105b94e232SMartin K. Petersen #define DEF_DIX 0
1115b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1121da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1135b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1145b94e232SMartin K. Petersen #define DEF_GUARD 0
115cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1165b94e232SMartin K. Petersen #define DEF_LBPU 0
1175b94e232SMartin K. Petersen #define DEF_LBPWS 0
1185b94e232SMartin K. Petersen #define DEF_LBPWS10 0
119be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1205b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
121cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1225b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1231da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1241da177e4SLinus Torvalds #define DEF_OPTS   0
125e308b3d1SMartin K. Petersen #define DEF_OPT_BLKS 64
1265b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
1275b94e232SMartin K. Petersen #define DEF_PTYPE   0
128d986788bSMartin Pitt #define DEF_REMOVABLE false
129e46b0344SDouglas Gilbert #define DEF_SCSI_LEVEL   6    /* INQUIRY, byte2 [6->SPC-4] */
1305b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1315b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1325b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1336014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1346014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1355b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1365b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1375b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
138c2248fc9SDouglas Gilbert #define DEF_STRICT 0
139cbf67842SDouglas Gilbert #define DELAY_OVERRIDDEN -9999
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */
1421da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE   1
1431da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR   2
1441da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT   4
1451da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR   8
1466f3cbf55SDouglas Gilbert #define SCSI_DEBUG_OPT_TRANSPORT_ERR   16
147c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIF_ERR   32
148c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIX_ERR   64
14918a4d0a2SMartin K. Petersen #define SCSI_DEBUG_OPT_MAC_TIMEOUT  128
150cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_SHORT_TRANSFER	0x100
151cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_Q_NOISE	0x200
152cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_ALL_TSF	0x400
153cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_RARE_TSF	0x800
154cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_N_WCE	0x1000
155cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_RESET_NOISE 0x2000
156cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_NO_CDB_NOISE 0x4000
157cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_ALL_NOISE (0x1 | 0x200 | 0x2000)
1581da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
1591da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1601da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1611da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1626f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1636f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1641da177e4SLinus Torvalds  *
1651da177e4SLinus Torvalds  * When "every_nth" < 0 then after "- 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  * This will continue until some other action occurs (e.g. the user
1721da177e4SLinus Torvalds  * writing a new value (other than -1 or 1) to every_nth via sysfs).
1731da177e4SLinus Torvalds  */
1741da177e4SLinus Torvalds 
175cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs)are returned in
176cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
177cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
178cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
179cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
180cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1
181cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2
1820d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3
1830d01c5dfSDouglas Gilbert #define SDEBUG_NUM_UAS 4
184cbf67842SDouglas Gilbert 
185cbf67842SDouglas Gilbert /* for check_readiness() */
186c2248fc9SDouglas Gilbert #define UAS_ONLY 1	/* check for UAs only */
187c2248fc9SDouglas Gilbert #define UAS_TUR 0	/* if no UAs then check if media access possible */
188cbf67842SDouglas Gilbert 
1891da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
1901da177e4SLinus Torvalds  * sector on read commands: */
1911da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
19232f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
1951da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
1961da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
197c65b1445SDouglas Gilbert #define SAM2_WLUN_REPORT_LUNS 0xc101
1981da177e4SLinus Torvalds 
199cbf67842SDouglas Gilbert /* SCSI_DEBUG_CANQUEUE is the maximum number of commands that can be queued
200cbf67842SDouglas Gilbert  * (for response) at one time. Can be reduced by max_queue option. Command
201cbf67842SDouglas Gilbert  * responses are not queued when delay=0 and ndelay=0. The per-device
202cbf67842SDouglas Gilbert  * DEF_CMD_PER_LUN can be changed via sysfs:
203cbf67842SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth but cannot exceed
204cbf67842SDouglas Gilbert  * SCSI_DEBUG_CANQUEUE. */
205cbf67842SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE_WORDS  9	/* a WORD is bits in a long */
206cbf67842SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE  (SCSI_DEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
207cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN  255
208cbf67842SDouglas Gilbert 
209cbf67842SDouglas Gilbert #if DEF_CMD_PER_LUN > SCSI_DEBUG_CANQUEUE
210cbf67842SDouglas Gilbert #warning "Expect DEF_CMD_PER_LUN <= SCSI_DEBUG_CANQUEUE"
211cbf67842SDouglas Gilbert #endif
21278d4e5a0SDouglas Gilbert 
213c2248fc9SDouglas Gilbert /* SCSI opcodes (first byte of cdb) mapped onto these indexes */
214c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
215c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
216c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
217c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
218c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
219c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
220c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
221c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
222c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
223c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
224c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
225c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
226c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
227c2248fc9SDouglas Gilbert 	SDEB_I_SERV_ACT_IN = 12,	/* 12, 16 */
228c2248fc9SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT = 13,	/* 12, 16 */
229c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
230c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
231c2248fc9SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* 10 only */
232c2248fc9SDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,
233c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
234c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
235c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
236c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
237c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
238c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
239c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
240c2248fc9SDouglas Gilbert 	SDEB_I_XDWRITEREAD = 25,	/* 10 only */
241c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_BUFFER = 26,
242c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_SAME = 27,		/* 10, 16 */
243c2248fc9SDouglas Gilbert 	SDEB_I_SYNC_CACHE = 28,		/* 10 only */
244c2248fc9SDouglas Gilbert 	SDEB_I_COMP_WRITE = 29,
245c2248fc9SDouglas Gilbert 	SDEB_I_LAST_ELEMENT = 30,	/* keep this last */
246c2248fc9SDouglas Gilbert };
247c2248fc9SDouglas Gilbert 
248c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
249c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
250c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
251c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
252c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
253c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
254c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
255c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
256c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
257c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
258c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
259c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
260c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
261c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
262c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
263c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
264c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
265c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
266c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
267c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
268c2248fc9SDouglas Gilbert /* 0x60; 0x60->0x7d are reserved */
269c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
270c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
271c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
272c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
273c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
274c2248fc9SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
275c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
276c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT,
277c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
278c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
279c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
280c2248fc9SDouglas Gilbert 	SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN,
281c2248fc9SDouglas Gilbert 	     0, 0, 0, 0,
282c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
283c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
284c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
285c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
286c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
287c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
288c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
289c2248fc9SDouglas Gilbert };
290c2248fc9SDouglas Gilbert 
291c2248fc9SDouglas Gilbert #define F_D_IN			1
292c2248fc9SDouglas Gilbert #define F_D_OUT			2
293c2248fc9SDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
294c2248fc9SDouglas Gilbert #define F_D_UNKN		8
295c2248fc9SDouglas Gilbert #define F_RL_WLUN_OK		0x10
296c2248fc9SDouglas Gilbert #define F_SKIP_UA		0x20
297c2248fc9SDouglas Gilbert #define F_DELAY_OVERR		0x40
298c2248fc9SDouglas Gilbert #define F_SA_LOW		0x80	/* cdb byte 1, bits 4 to 0 */
299c2248fc9SDouglas Gilbert #define F_SA_HIGH		0x100	/* as used by variable length cdbs */
300c2248fc9SDouglas Gilbert #define F_INV_OP		0x200
301c2248fc9SDouglas Gilbert #define F_FAKE_RW		0x400
302c2248fc9SDouglas Gilbert #define F_M_ACCESS		0x800	/* media access */
303c2248fc9SDouglas Gilbert 
304c2248fc9SDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
305c2248fc9SDouglas Gilbert #define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW)
306c2248fc9SDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
307c2248fc9SDouglas Gilbert 
308c2248fc9SDouglas Gilbert struct sdebug_dev_info;
309c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
310c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
311c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
312c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
313c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
314c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
315c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
316c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
317c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
318c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
319c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
320c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
321c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
322c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
32338d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
32438d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
325c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
326c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
327c2248fc9SDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
32838d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
329c2248fc9SDouglas Gilbert 
330c2248fc9SDouglas Gilbert struct opcode_info_t {
331c2248fc9SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff
332c2248fc9SDouglas Gilbert 				 * for terminating element */
333c2248fc9SDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
334c2248fc9SDouglas Gilbert 	u16 sa;			/* service action */
335c2248fc9SDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
336c2248fc9SDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
337c2248fc9SDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
338c2248fc9SDouglas Gilbert 	u8 len_mask[16];	/* len=len_mask[0], then mask for cdb[1]... */
339c2248fc9SDouglas Gilbert 				/* ignore cdb bytes after position 15 */
340c2248fc9SDouglas Gilbert };
341c2248fc9SDouglas Gilbert 
342c2248fc9SDouglas Gilbert static const struct opcode_info_t msense_iarr[1] = {
343c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
344c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
345c2248fc9SDouglas Gilbert };
346c2248fc9SDouglas Gilbert 
347c2248fc9SDouglas Gilbert static const struct opcode_info_t mselect_iarr[1] = {
348c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
349c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
350c2248fc9SDouglas Gilbert };
351c2248fc9SDouglas Gilbert 
352c2248fc9SDouglas Gilbert static const struct opcode_info_t read_iarr[3] = {
353c2248fc9SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */
354c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
355c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
356c2248fc9SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */
357c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
358c2248fc9SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */
359c2248fc9SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
360c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
361c2248fc9SDouglas Gilbert };
362c2248fc9SDouglas Gilbert 
363c2248fc9SDouglas Gilbert static const struct opcode_info_t write_iarr[3] = {
364c2248fc9SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,   /* 10 */
365c2248fc9SDouglas Gilbert 	    {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
366c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
367c2248fc9SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,    /* 6 */
368c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
369c2248fc9SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,   /* 12 */
370c2248fc9SDouglas Gilbert 	    {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
371c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
372c2248fc9SDouglas Gilbert };
373c2248fc9SDouglas Gilbert 
374c2248fc9SDouglas Gilbert static const struct opcode_info_t sa_in_iarr[1] = {
375c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
376c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
377c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },
378c2248fc9SDouglas Gilbert };
379c2248fc9SDouglas Gilbert 
380c2248fc9SDouglas Gilbert static const struct opcode_info_t vl_iarr[1] = {	/* VARIABLE LENGTH */
381c2248fc9SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0,
382c2248fc9SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa,
383c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
384c2248fc9SDouglas Gilbert };
385c2248fc9SDouglas Gilbert 
386c2248fc9SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[2] = {
38738d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
388c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
389c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
39038d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
391c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
392c2248fc9SDouglas Gilbert 	     0, 0} },
393c2248fc9SDouglas Gilbert };
394c2248fc9SDouglas Gilbert 
395c2248fc9SDouglas Gilbert static const struct opcode_info_t write_same_iarr[1] = {
396c2248fc9SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL,
397c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
398c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x1f, 0xc7} },
399c2248fc9SDouglas Gilbert };
400c2248fc9SDouglas Gilbert 
401c2248fc9SDouglas Gilbert static const struct opcode_info_t reserve_iarr[1] = {
402c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,	/* RESERVE(6) */
403c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
404c2248fc9SDouglas Gilbert };
405c2248fc9SDouglas Gilbert 
406c2248fc9SDouglas Gilbert static const struct opcode_info_t release_iarr[1] = {
407c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,	/* RELEASE(6) */
408c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
409c2248fc9SDouglas Gilbert };
410c2248fc9SDouglas Gilbert 
411c2248fc9SDouglas Gilbert 
412c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
413c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
414c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
415c2248fc9SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
416c2248fc9SDouglas Gilbert /* 0 */
417c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,
418c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
419c2248fc9SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL,
420c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
421c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
422c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
423c2248fc9SDouglas Gilbert 	     0, 0} },
424c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
425c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
426c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
427c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
428c2248fc9SDouglas Gilbert 	{1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr,
429c2248fc9SDouglas Gilbert 	    {10,  0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
430c2248fc9SDouglas Gilbert 	     0} },
431c2248fc9SDouglas Gilbert 	{1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr,
432c2248fc9SDouglas Gilbert 	    {10,  0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
433c2248fc9SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,
434c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
435c2248fc9SDouglas Gilbert 	     0, 0, 0} },
436c2248fc9SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,
437c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
438c2248fc9SDouglas Gilbert 	     0, 0} },
439c2248fc9SDouglas Gilbert 	{3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr,
440c2248fc9SDouglas Gilbert 	    {16,  0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
441c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x9f, 0xc7} },		/* READ(16) */
442c2248fc9SDouglas Gilbert /* 10 */
443c2248fc9SDouglas Gilbert 	{3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr,
444c2248fc9SDouglas Gilbert 	    {16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
445c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x9f, 0xc7} },		/* WRITE(16) */
446c2248fc9SDouglas Gilbert 	{0, 0x1b, 0, 0, resp_start_stop, NULL,		/* START STOP UNIT */
447c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
448c2248fc9SDouglas Gilbert 	{1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr,
449c2248fc9SDouglas Gilbert 	    {16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
450c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x1, 0xc7} },	/* READ CAPACITY(16) */
451c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */
452c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
453c2248fc9SDouglas Gilbert 	{2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr,
454c2248fc9SDouglas Gilbert 	    {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0,
455c2248fc9SDouglas Gilbert 	     0} },
456c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
457c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
458c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* VERIFY */
459c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
460c2248fc9SDouglas Gilbert 	{1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0,
461c2248fc9SDouglas Gilbert 	    vl_iarr, {32,  0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0,
462c2248fc9SDouglas Gilbert 		      0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */
463c2248fc9SDouglas Gilbert 	{1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */
464c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
465c2248fc9SDouglas Gilbert 	     0} },
466c2248fc9SDouglas Gilbert 	{1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */
467c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
468c2248fc9SDouglas Gilbert 	     0} },
469c2248fc9SDouglas Gilbert /* 20 */
470c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ALLOW REMOVAL */
471c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
472c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
473c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
474c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
475c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
476c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
477c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
478c2248fc9SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */
479c2248fc9SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
480c2248fc9SDouglas Gilbert 	{0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10,
481c2248fc9SDouglas Gilbert 	    NULL, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7,
482c2248fc9SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
483c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* WRITE_BUFFER */
484c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
485c2248fc9SDouglas Gilbert 	{1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10,
486c2248fc9SDouglas Gilbert 	    write_same_iarr, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff,
487c2248fc9SDouglas Gilbert 			      0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
488c2248fc9SDouglas Gilbert 	{0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */
489c2248fc9SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
490c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
49138d5c833SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL,
492c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
493c2248fc9SDouglas Gilbert 	     0, 0xff, 0x1f, 0xc7} },		/* COMPARE AND WRITE */
494c2248fc9SDouglas Gilbert 
495c2248fc9SDouglas Gilbert /* 30 */
496c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
497c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
498c2248fc9SDouglas Gilbert };
499c2248fc9SDouglas Gilbert 
500817fd66bSDouglas Gilbert struct sdebug_scmd_extra_t {
501817fd66bSDouglas Gilbert 	bool inj_recovered;
502817fd66bSDouglas Gilbert 	bool inj_transport;
503817fd66bSDouglas Gilbert 	bool inj_dif;
504817fd66bSDouglas Gilbert 	bool inj_dix;
505817fd66bSDouglas Gilbert 	bool inj_short;
506817fd66bSDouglas Gilbert };
507817fd66bSDouglas Gilbert 
5081da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST;
5095b94e232SMartin K. Petersen static int scsi_debug_ato = DEF_ATO;
5101da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY;
5111da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
5125b94e232SMartin K. Petersen static int scsi_debug_dif = DEF_DIF;
5135b94e232SMartin K. Petersen static int scsi_debug_dix = DEF_DIX;
5145b94e232SMartin K. Petersen static int scsi_debug_dsense = DEF_D_SENSE;
5151da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH;
5165b94e232SMartin K. Petersen static int scsi_debug_fake_rw = DEF_FAKE_RW;
51768aee7baSAkinobu Mita static unsigned int scsi_debug_guard = DEF_GUARD;
5185b94e232SMartin K. Petersen static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
5191da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS;
52078d4e5a0SDouglas Gilbert static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE;
521cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
522cbf67842SDouglas Gilbert static int scsi_debug_ndelay = DEF_NDELAY;
523c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
5245b94e232SMartin K. Petersen static int scsi_debug_no_uld = 0;
5255b94e232SMartin K. Petersen static int scsi_debug_num_parts = DEF_NUM_PARTS;
5265b94e232SMartin K. Petersen static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
527e308b3d1SMartin K. Petersen static int scsi_debug_opt_blks = DEF_OPT_BLKS;
5285b94e232SMartin K. Petersen static int scsi_debug_opts = DEF_OPTS;
5295b94e232SMartin K. Petersen static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
5305b94e232SMartin K. Petersen static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
5315b94e232SMartin K. Petersen static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
5325b94e232SMartin K. Petersen static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
5335b94e232SMartin K. Petersen static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
5345b94e232SMartin K. Petersen static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
5355b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpu = DEF_LBPU;
5365b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws = DEF_LBPWS;
5375b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10;
538be1dd78dSEric Sandeen static unsigned int scsi_debug_lbprz = DEF_LBPRZ;
5396014759cSMartin K. Petersen static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
5405b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
5415b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
5425b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
5435b94e232SMartin K. Petersen static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH;
544d986788bSMartin Pitt static bool scsi_debug_removable = DEF_REMOVABLE;
5450759c666SAkinobu Mita static bool scsi_debug_clustering;
546cbf67842SDouglas Gilbert static bool scsi_debug_host_lock = DEF_HOST_LOCK;
547c2248fc9SDouglas Gilbert static bool scsi_debug_strict = DEF_STRICT;
548817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
5491da177e4SLinus Torvalds 
550cbf67842SDouglas Gilbert static atomic_t sdebug_cmnd_count;
551cbf67842SDouglas Gilbert static atomic_t sdebug_completions;
552cbf67842SDouglas Gilbert static atomic_t sdebug_a_tsf;		/* counter of 'almost' TSFs */
5531da177e4SLinus Torvalds 
5541da177e4SLinus Torvalds #define DEV_READONLY(TGT)      (0)
5551da177e4SLinus Torvalds 
556c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
5571da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
5581da177e4SLinus Torvalds 
5591da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
5601da177e4SLinus Torvalds    may still need them */
5611da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
5621da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
5631da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
5641da177e4SLinus Torvalds 
5651da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4
5661da177e4SLinus Torvalds 
567395cef03SMartin K. Petersen #define SCSI_DEBUG_MAX_CMD_LEN 32
5689e603ca0SFUJITA Tomonori 
5695b94e232SMartin K. Petersen static unsigned int scsi_debug_lbp(void)
5705b94e232SMartin K. Petersen {
571cbf67842SDouglas Gilbert 	return ((0 == scsi_debug_fake_rw) &&
572cbf67842SDouglas Gilbert 		(scsi_debug_lbpu | scsi_debug_lbpws | scsi_debug_lbpws10));
5735b94e232SMartin K. Petersen }
5745b94e232SMartin K. Petersen 
5751da177e4SLinus Torvalds struct sdebug_dev_info {
5761da177e4SLinus Torvalds 	struct list_head dev_list;
5771da177e4SLinus Torvalds 	unsigned int channel;
5781da177e4SLinus Torvalds 	unsigned int target;
5799cb78c16SHannes Reinecke 	u64 lun;
5801da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
581cbf67842SDouglas Gilbert 	unsigned long uas_bm[1];
582cbf67842SDouglas Gilbert 	atomic_t num_in_q;
583c2248fc9SDouglas Gilbert 	char stopped;		/* TODO: should be atomic */
584c2248fc9SDouglas Gilbert 	bool used;
5851da177e4SLinus Torvalds };
5861da177e4SLinus Torvalds 
5871da177e4SLinus Torvalds struct sdebug_host_info {
5881da177e4SLinus Torvalds 	struct list_head host_list;
5891da177e4SLinus Torvalds 	struct Scsi_Host *shost;
5901da177e4SLinus Torvalds 	struct device dev;
5911da177e4SLinus Torvalds 	struct list_head dev_info_list;
5921da177e4SLinus Torvalds };
5931da177e4SLinus Torvalds 
5941da177e4SLinus Torvalds #define to_sdebug_host(d)	\
5951da177e4SLinus Torvalds 	container_of(d, struct sdebug_host_info, dev)
5961da177e4SLinus Torvalds 
5971da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
5981da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
5991da177e4SLinus Torvalds 
600cbf67842SDouglas Gilbert 
601cbf67842SDouglas Gilbert struct sdebug_hrtimer {		/* ... is derived from hrtimer */
602cbf67842SDouglas Gilbert 	struct hrtimer hrt;	/* must be first element */
603cbf67842SDouglas Gilbert 	int qa_indx;
604cbf67842SDouglas Gilbert };
6051da177e4SLinus Torvalds 
6061da177e4SLinus Torvalds struct sdebug_queued_cmd {
607cbf67842SDouglas Gilbert 	/* in_use flagged by a bit in queued_in_use_bm[] */
608cbf67842SDouglas Gilbert 	struct timer_list *cmnd_timerp;
609cbf67842SDouglas Gilbert 	struct tasklet_struct *tletp;
610cbf67842SDouglas Gilbert 	struct sdebug_hrtimer *sd_hrtp;
6111da177e4SLinus Torvalds 	struct scsi_cmnd * a_cmnd;
6121da177e4SLinus Torvalds };
6131da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
614cbf67842SDouglas Gilbert static unsigned long queued_in_use_bm[SCSI_DEBUG_CANQUEUE_WORDS];
615cbf67842SDouglas Gilbert 
6161da177e4SLinus Torvalds 
6171da177e4SLinus Torvalds static unsigned char * fake_storep;	/* ramdisk storage */
618e18d8beaSAkinobu Mita static struct sd_dif_tuple *dif_storep;	/* protection info */
61944d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
6201da177e4SLinus Torvalds 
62144d92694SMartin K. Petersen static unsigned long map_size;
622cbf67842SDouglas Gilbert static int num_aborts;
623cbf67842SDouglas Gilbert static int num_dev_resets;
624cbf67842SDouglas Gilbert static int num_target_resets;
625cbf67842SDouglas Gilbert static int num_bus_resets;
626cbf67842SDouglas Gilbert static int num_host_resets;
627c6a44287SMartin K. Petersen static int dix_writes;
628c6a44287SMartin K. Petersen static int dix_reads;
629c6a44287SMartin K. Petersen static int dif_errors;
6301da177e4SLinus Torvalds 
6311da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock);
6321da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
6331da177e4SLinus Torvalds 
634cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
635cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
6361da177e4SLinus Torvalds 
6371da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
6381da177e4SLinus Torvalds 
6391da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
6401da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
6411da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
6421da177e4SLinus Torvalds };
6431da177e4SLinus Torvalds 
6441da177e4SLinus Torvalds static const int check_condition_result =
6451da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
6461da177e4SLinus Torvalds 
647c6a44287SMartin K. Petersen static const int illegal_condition_result =
648c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
649c6a44287SMartin K. Petersen 
650cbf67842SDouglas Gilbert static const int device_qfull_result =
651cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
652cbf67842SDouglas Gilbert 
653cbf67842SDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
654cbf67842SDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
655cbf67842SDouglas Gilbert 				     0, 0, 0, 0};
656c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
657c65b1445SDouglas Gilbert 				    0, 0, 0x2, 0x4b};
658c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
659c65b1445SDouglas Gilbert 			           0, 0, 0x0, 0x0};
660c65b1445SDouglas Gilbert 
66114faa944SAkinobu Mita static void *fake_store(unsigned long long lba)
66214faa944SAkinobu Mita {
66314faa944SAkinobu Mita 	lba = do_div(lba, sdebug_store_sectors);
66414faa944SAkinobu Mita 
66514faa944SAkinobu Mita 	return fake_storep + lba * scsi_debug_sector_size;
66614faa944SAkinobu Mita }
66714faa944SAkinobu Mita 
66814faa944SAkinobu Mita static struct sd_dif_tuple *dif_store(sector_t sector)
66914faa944SAkinobu Mita {
67014faa944SAkinobu Mita 	sector = do_div(sector, sdebug_store_sectors);
67114faa944SAkinobu Mita 
67214faa944SAkinobu Mita 	return dif_storep + sector;
67314faa944SAkinobu Mita }
67414faa944SAkinobu Mita 
6751da177e4SLinus Torvalds static int sdebug_add_adapter(void);
6761da177e4SLinus Torvalds static void sdebug_remove_adapter(void);
6771da177e4SLinus Torvalds 
6788dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
6798dea0d02SFUJITA Tomonori {
6808dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
6818dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
6828dea0d02SFUJITA Tomonori 
6838dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
6848dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
6858dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
6868dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
6878dea0d02SFUJITA Tomonori 		    (scsi_debug_num_tgts > hpnt->this_id))
6888dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts + 1;
6898dea0d02SFUJITA Tomonori 		else
6908dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts;
6918dea0d02SFUJITA Tomonori 		/* scsi_debug_max_luns; */
6928dea0d02SFUJITA Tomonori 		hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
6938dea0d02SFUJITA Tomonori 	}
6948dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
6958dea0d02SFUJITA Tomonori }
6968dea0d02SFUJITA Tomonori 
69722017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
69822017ed2SDouglas Gilbert 
69922017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
70022017ed2SDouglas Gilbert static void
70122017ed2SDouglas Gilbert mk_sense_invalid_fld(struct scsi_cmnd *scp, enum sdeb_cmd_data c_d,
70222017ed2SDouglas Gilbert 		     int in_byte, int in_bit)
70322017ed2SDouglas Gilbert {
70422017ed2SDouglas Gilbert 	unsigned char *sbuff;
70522017ed2SDouglas Gilbert 	u8 sks[4];
70622017ed2SDouglas Gilbert 	int sl, asc;
70722017ed2SDouglas Gilbert 
70822017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
70922017ed2SDouglas Gilbert 	if (!sbuff) {
71022017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
71122017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
71222017ed2SDouglas Gilbert 		return;
71322017ed2SDouglas Gilbert 	}
71422017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
71522017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
71622017ed2SDouglas Gilbert 	scsi_build_sense_buffer(scsi_debug_dsense, sbuff, ILLEGAL_REQUEST,
71722017ed2SDouglas Gilbert 				asc, 0);
71822017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
71922017ed2SDouglas Gilbert 	sks[0] = 0x80;
72022017ed2SDouglas Gilbert 	if (c_d)
72122017ed2SDouglas Gilbert 		sks[0] |= 0x40;
72222017ed2SDouglas Gilbert 	if (in_bit >= 0) {
72322017ed2SDouglas Gilbert 		sks[0] |= 0x8;
72422017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
72522017ed2SDouglas Gilbert 	}
72622017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
72722017ed2SDouglas Gilbert 	if (scsi_debug_dsense) {
72822017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
72922017ed2SDouglas Gilbert 		sbuff[7] = sl;
73022017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
73122017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
73222017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
73322017ed2SDouglas Gilbert 	} else
73422017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
73522017ed2SDouglas Gilbert 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
73622017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
73722017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
73822017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
73922017ed2SDouglas Gilbert }
74022017ed2SDouglas Gilbert 
741cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
7428dea0d02SFUJITA Tomonori {
7438dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
7448dea0d02SFUJITA Tomonori 
745cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
746cbf67842SDouglas Gilbert 	if (!sbuff) {
747cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
748cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
749cbf67842SDouglas Gilbert 		return;
750cbf67842SDouglas Gilbert 	}
751cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
7528dea0d02SFUJITA Tomonori 
7538dea0d02SFUJITA Tomonori 	scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
7548dea0d02SFUJITA Tomonori 
7558dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
756cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
757cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
758cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
7598dea0d02SFUJITA Tomonori }
7601da177e4SLinus Torvalds 
76122017ed2SDouglas Gilbert static void
76222017ed2SDouglas Gilbert mk_sense_invalid_opcode(struct scsi_cmnd *scp)
76322017ed2SDouglas Gilbert {
76422017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
76522017ed2SDouglas Gilbert }
76622017ed2SDouglas Gilbert 
7671da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
7681da177e4SLinus Torvalds {
7691da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
770cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
771cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
772cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
773cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
774cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
775cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
776cbf67842SDouglas Gilbert 				    __func__);
777cbf67842SDouglas Gilbert 		else
778cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
779cbf67842SDouglas Gilbert 				    __func__, cmd);
7801da177e4SLinus Torvalds 	}
7811da177e4SLinus Torvalds 	return -EINVAL;
7821da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
7831da177e4SLinus Torvalds }
7841da177e4SLinus Torvalds 
785cbf67842SDouglas Gilbert static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only,
786c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
7871da177e4SLinus Torvalds {
788cbf67842SDouglas Gilbert 	int k;
789cbf67842SDouglas Gilbert 	bool debug = !!(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts);
790cbf67842SDouglas Gilbert 
791cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
792cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
793cbf67842SDouglas Gilbert 		const char *cp = NULL;
794cbf67842SDouglas Gilbert 
795cbf67842SDouglas Gilbert 		switch (k) {
796cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
797cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
798cbf67842SDouglas Gilbert 					UA_RESET_ASC, POWER_ON_RESET_ASCQ);
799cbf67842SDouglas Gilbert 			if (debug)
800cbf67842SDouglas Gilbert 				cp = "power on reset";
801cbf67842SDouglas Gilbert 			break;
802cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
803cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
804cbf67842SDouglas Gilbert 					UA_RESET_ASC, BUS_RESET_ASCQ);
805cbf67842SDouglas Gilbert 			if (debug)
806cbf67842SDouglas Gilbert 				cp = "bus reset";
807cbf67842SDouglas Gilbert 			break;
808cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
809cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
810cbf67842SDouglas Gilbert 					UA_CHANGED_ASC, MODE_CHANGED_ASCQ);
811cbf67842SDouglas Gilbert 			if (debug)
812cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
813cbf67842SDouglas Gilbert 			break;
8140d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
8150d01c5dfSDouglas Gilbert 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
8160d01c5dfSDouglas Gilbert 					UA_CHANGED_ASC, CAPACITY_CHANGED_ASCQ);
8170d01c5dfSDouglas Gilbert 			if (debug)
8180d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
819cbf67842SDouglas Gilbert 		default:
820cbf67842SDouglas Gilbert 			pr_warn("%s: unexpected unit attention code=%d\n",
821cbf67842SDouglas Gilbert 				__func__, k);
822cbf67842SDouglas Gilbert 			if (debug)
823cbf67842SDouglas Gilbert 				cp = "unknown";
824cbf67842SDouglas Gilbert 			break;
825cbf67842SDouglas Gilbert 		}
826cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
827cbf67842SDouglas Gilbert 		if (debug)
828cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
829cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
830cbf67842SDouglas Gilbert 				   my_name, cp);
8311da177e4SLinus Torvalds 		return check_condition_result;
8321da177e4SLinus Torvalds 	}
833cbf67842SDouglas Gilbert 	if ((UAS_TUR == uas_only) && devip->stopped) {
834cbf67842SDouglas Gilbert 		mk_sense_buffer(SCpnt, NOT_READY, LOGICAL_UNIT_NOT_READY,
835c65b1445SDouglas Gilbert 				0x2);
836cbf67842SDouglas Gilbert 		if (debug)
837cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
838cbf67842SDouglas Gilbert 				    "%s reports: Not ready: %s\n", my_name,
839cbf67842SDouglas Gilbert 				    "initializing command required");
840c65b1445SDouglas Gilbert 		return check_condition_result;
841c65b1445SDouglas Gilbert 	}
8421da177e4SLinus Torvalds 	return 0;
8431da177e4SLinus Torvalds }
8441da177e4SLinus Torvalds 
8451da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
8461da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
8471da177e4SLinus Torvalds 				int arr_len)
8481da177e4SLinus Torvalds {
84921a61829SFUJITA Tomonori 	int act_len;
850072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
8511da177e4SLinus Torvalds 
852072d0bb3SFUJITA Tomonori 	if (!sdb->length)
8531da177e4SLinus Torvalds 		return 0;
854072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
8551da177e4SLinus Torvalds 		return (DID_ERROR << 16);
85621a61829SFUJITA Tomonori 
85721a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
85821a61829SFUJITA Tomonori 				      arr, arr_len);
85921a61829SFUJITA Tomonori 	sdb->resid = scsi_bufflen(scp) - act_len;
86021a61829SFUJITA Tomonori 
8611da177e4SLinus Torvalds 	return 0;
8621da177e4SLinus Torvalds }
8631da177e4SLinus Torvalds 
8641da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */
8651da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
86621a61829SFUJITA Tomonori 			       int arr_len)
8671da177e4SLinus Torvalds {
86821a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
8691da177e4SLinus Torvalds 		return 0;
870072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
8711da177e4SLinus Torvalds 		return -1;
87221a61829SFUJITA Tomonori 
87321a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
8741da177e4SLinus Torvalds }
8751da177e4SLinus Torvalds 
8761da177e4SLinus Torvalds 
8771da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux   ";
8781da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug      ";
879cbf67842SDouglas Gilbert static const char *inq_product_rev = "0184";	/* version less '.' */
8801da177e4SLinus Torvalds 
881cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
8825a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
8835a09e398SHannes Reinecke 			   int target_dev_id, int dev_id_num,
8845a09e398SHannes Reinecke 			   const char * dev_id_str,
885c65b1445SDouglas Gilbert 			   int dev_id_str_len)
8861da177e4SLinus Torvalds {
887c65b1445SDouglas Gilbert 	int num, port_a;
888c65b1445SDouglas Gilbert 	char b[32];
8891da177e4SLinus Torvalds 
890c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
8911da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
8921da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
8931da177e4SLinus Torvalds 	arr[1] = 0x1;
8941da177e4SLinus Torvalds 	arr[2] = 0x0;
8951da177e4SLinus Torvalds 	memcpy(&arr[4], inq_vendor_id, 8);
8961da177e4SLinus Torvalds 	memcpy(&arr[12], inq_product_id, 16);
8971da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
8981da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
8991da177e4SLinus Torvalds 	arr[3] = num;
9001da177e4SLinus Torvalds 	num += 4;
901c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
902c65b1445SDouglas Gilbert 		/* NAA-5, Logical unit identifier (binary) */
903c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* binary (not necessarily sas) */
904c65b1445SDouglas Gilbert 		arr[num++] = 0x3;	/* PIV=0, lu, naa */
905c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
906c65b1445SDouglas Gilbert 		arr[num++] = 0x8;
907c65b1445SDouglas Gilbert 		arr[num++] = 0x53;  /* naa-5 ieee company id=0x333333 (fake) */
908c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
909c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
910c65b1445SDouglas Gilbert 		arr[num++] = 0x30;
911c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 24);
912c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 16) & 0xff;
913c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 8) & 0xff;
914c65b1445SDouglas Gilbert 		arr[num++] = dev_id_num & 0xff;
915c65b1445SDouglas Gilbert 		/* Target relative port number */
916c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
917c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
918c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
919c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
920c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
921c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
922c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
923c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
924c65b1445SDouglas Gilbert 	}
925c65b1445SDouglas Gilbert 	/* NAA-5, Target port identifier */
926c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
927c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
928c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
929c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
930c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
931c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
932c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
933c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
934c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
935c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
936c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
937c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
9385a09e398SHannes Reinecke 	/* NAA-5, Target port group identifier */
9395a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
9405a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
9415a09e398SHannes Reinecke 	arr[num++] = 0x0;
9425a09e398SHannes Reinecke 	arr[num++] = 0x4;
9435a09e398SHannes Reinecke 	arr[num++] = 0;
9445a09e398SHannes Reinecke 	arr[num++] = 0;
9455a09e398SHannes Reinecke 	arr[num++] = (port_group_id >> 8) & 0xff;
9465a09e398SHannes Reinecke 	arr[num++] = port_group_id & 0xff;
947c65b1445SDouglas Gilbert 	/* NAA-5, Target device identifier */
948c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
949c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
950c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
951c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
952c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
953c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
954c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
955c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
956c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 24);
957c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 16) & 0xff;
958c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 8) & 0xff;
959c65b1445SDouglas Gilbert 	arr[num++] = target_dev_id & 0xff;
960c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
961c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
962c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
963c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
964c65b1445SDouglas Gilbert 	arr[num++] = 24;
965c65b1445SDouglas Gilbert 	memcpy(arr + num, "naa.52222220", 12);
966c65b1445SDouglas Gilbert 	num += 12;
967c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
968c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
969c65b1445SDouglas Gilbert 	num += 8;
970c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
971c65b1445SDouglas Gilbert 	num += 4;
972c65b1445SDouglas Gilbert 	return num;
973c65b1445SDouglas Gilbert }
974c65b1445SDouglas Gilbert 
975c65b1445SDouglas Gilbert 
976c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
977c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
978c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
979c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
980c65b1445SDouglas Gilbert };
981c65b1445SDouglas Gilbert 
982cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
983c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr)
984c65b1445SDouglas Gilbert {
985c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
986c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
987c65b1445SDouglas Gilbert }
988c65b1445SDouglas Gilbert 
989cbf67842SDouglas Gilbert /* Management network addresses VPD page */
990c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr)
991c65b1445SDouglas Gilbert {
992c65b1445SDouglas Gilbert 	int num = 0;
993c65b1445SDouglas Gilbert 	const char * na1 = "https://www.kernel.org/config";
994c65b1445SDouglas Gilbert 	const char * na2 = "http://www.kernel.org/log";
995c65b1445SDouglas Gilbert 	int plen, olen;
996c65b1445SDouglas Gilbert 
997c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
998c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
999c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1000c65b1445SDouglas Gilbert 	olen = strlen(na1);
1001c65b1445SDouglas Gilbert 	plen = olen + 1;
1002c65b1445SDouglas Gilbert 	if (plen % 4)
1003c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1004c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1005c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1006c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1007c65b1445SDouglas Gilbert 	num += plen;
1008c65b1445SDouglas Gilbert 
1009c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1010c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1011c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1012c65b1445SDouglas Gilbert 	olen = strlen(na2);
1013c65b1445SDouglas Gilbert 	plen = olen + 1;
1014c65b1445SDouglas Gilbert 	if (plen % 4)
1015c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1016c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1017c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1018c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1019c65b1445SDouglas Gilbert 	num += plen;
1020c65b1445SDouglas Gilbert 
1021c65b1445SDouglas Gilbert 	return num;
1022c65b1445SDouglas Gilbert }
1023c65b1445SDouglas Gilbert 
1024c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1025c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
1026c65b1445SDouglas Gilbert {
1027c65b1445SDouglas Gilbert 	int num = 0;
1028c65b1445SDouglas Gilbert 	int port_a, port_b;
1029c65b1445SDouglas Gilbert 
1030c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1031c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1032c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1033c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1034c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1035c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1036c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1037c65b1445SDouglas Gilbert 	num += 6;
1038c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1039c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1040c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1041c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1042c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1043c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1044c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
1045c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
1046c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
1047c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
1048c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
1049c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
1050c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
1051c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
1052c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
1053c65b1445SDouglas Gilbert 
1054c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1055c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1056c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1057c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1058c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1059c65b1445SDouglas Gilbert 	num += 6;
1060c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1061c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1062c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1063c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1064c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1065c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1066c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
1067c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
1068c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
1069c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
1070c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
1071c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 24);
1072c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 16) & 0xff;
1073c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 8) & 0xff;
1074c65b1445SDouglas Gilbert 	arr[num++] = port_b & 0xff;
1075c65b1445SDouglas Gilbert 
1076c65b1445SDouglas Gilbert 	return num;
1077c65b1445SDouglas Gilbert }
1078c65b1445SDouglas Gilbert 
1079c65b1445SDouglas Gilbert 
1080c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1081c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1082c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1083c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1084c65b1445SDouglas Gilbert '1','2','3','4',
1085c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1086c65b1445SDouglas Gilbert 0xec,0,0,0,
1087c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1088c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1089c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1090c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1091c65b1445SDouglas Gilbert 0x53,0x41,
1092c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1093c65b1445SDouglas Gilbert 0x20,0x20,
1094c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1095c65b1445SDouglas Gilbert 0x10,0x80,
1096c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1097c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1098c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1099c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1100c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1101c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1102c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1103c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1104c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1105c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1106c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1107c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1108c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1109c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1110c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1111c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1112c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1113c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1114c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1115c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1116c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1117c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1118c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1119c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1120c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1121c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1122c65b1445SDouglas Gilbert };
1123c65b1445SDouglas Gilbert 
1124cbf67842SDouglas Gilbert /* ATA Information VPD page */
1125c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr)
1126c65b1445SDouglas Gilbert {
1127c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1128c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1129c65b1445SDouglas Gilbert }
1130c65b1445SDouglas Gilbert 
1131c65b1445SDouglas Gilbert 
1132c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
11331e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
11341e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11351e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11361e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1137c65b1445SDouglas Gilbert };
1138c65b1445SDouglas Gilbert 
1139cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1140c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr)
1141c65b1445SDouglas Gilbert {
1142ea61fca5SMartin K. Petersen 	unsigned int gran;
1143ea61fca5SMartin K. Petersen 
1144c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1145e308b3d1SMartin K. Petersen 
1146e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
1147ea61fca5SMartin K. Petersen 	gran = 1 << scsi_debug_physblk_exp;
1148ea61fca5SMartin K. Petersen 	arr[2] = (gran >> 8) & 0xff;
1149ea61fca5SMartin K. Petersen 	arr[3] = gran & 0xff;
1150e308b3d1SMartin K. Petersen 
1151e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1152c65b1445SDouglas Gilbert 	if (sdebug_store_sectors > 0x400) {
1153c65b1445SDouglas Gilbert 		arr[4] = (sdebug_store_sectors >> 24) & 0xff;
1154c65b1445SDouglas Gilbert 		arr[5] = (sdebug_store_sectors >> 16) & 0xff;
1155c65b1445SDouglas Gilbert 		arr[6] = (sdebug_store_sectors >> 8) & 0xff;
1156c65b1445SDouglas Gilbert 		arr[7] = sdebug_store_sectors & 0xff;
1157c65b1445SDouglas Gilbert 	}
115844d92694SMartin K. Petersen 
1159e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1160e308b3d1SMartin K. Petersen 	put_unaligned_be32(scsi_debug_opt_blks, &arr[8]);
1161e308b3d1SMartin K. Petersen 
11625b94e232SMartin K. Petersen 	if (scsi_debug_lbpu) {
1163e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
11646014759cSMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]);
1165e308b3d1SMartin K. Petersen 
1166e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
116744d92694SMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
116844d92694SMartin K. Petersen 	}
116944d92694SMartin K. Petersen 
1170e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
117144d92694SMartin K. Petersen 	if (scsi_debug_unmap_alignment) {
117244d92694SMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
117344d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
117444d92694SMartin K. Petersen 	}
117544d92694SMartin K. Petersen 
1176e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
117744d92694SMartin K. Petersen 	put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
11786014759cSMartin K. Petersen 
11795b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
11805b94e232SMartin K. Petersen 	put_unaligned_be64(scsi_debug_write_same_length, &arr[32]);
11815b94e232SMartin K. Petersen 
11825b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
118344d92694SMartin K. Petersen 
1184c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
11851da177e4SLinus Torvalds }
11861da177e4SLinus Torvalds 
11871e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
1188eac6e8e4SMatthew Wilcox static int inquiry_evpd_b1(unsigned char *arr)
1189eac6e8e4SMatthew Wilcox {
1190eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1191eac6e8e4SMatthew Wilcox 	arr[0] = 0;
11921e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
11931e49f785SDouglas Gilbert 	arr[2] = 0;
11941e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
1195eac6e8e4SMatthew Wilcox 
1196eac6e8e4SMatthew Wilcox 	return 0x3c;
1197eac6e8e4SMatthew Wilcox }
11981da177e4SLinus Torvalds 
1199be1dd78dSEric Sandeen /* Logical block provisioning VPD page (SBC-3) */
12006014759cSMartin K. Petersen static int inquiry_evpd_b2(unsigned char *arr)
12016014759cSMartin K. Petersen {
12023f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
12036014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
12046014759cSMartin K. Petersen 
12055b94e232SMartin K. Petersen 	if (scsi_debug_lbpu)
12066014759cSMartin K. Petersen 		arr[1] = 1 << 7;
12076014759cSMartin K. Petersen 
12085b94e232SMartin K. Petersen 	if (scsi_debug_lbpws)
12096014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
12106014759cSMartin K. Petersen 
12115b94e232SMartin K. Petersen 	if (scsi_debug_lbpws10)
12125b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
12135b94e232SMartin K. Petersen 
1214be1dd78dSEric Sandeen 	if (scsi_debug_lbprz)
1215be1dd78dSEric Sandeen 		arr[1] |= 1 << 2;
1216be1dd78dSEric Sandeen 
12173f0bc3b3SMartin K. Petersen 	return 0x4;
12186014759cSMartin K. Petersen }
12196014759cSMartin K. Petersen 
12201da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1221c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
12221da177e4SLinus Torvalds 
1223c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
12241da177e4SLinus Torvalds {
12251da177e4SLinus Torvalds 	unsigned char pq_pdt;
12265a09e398SHannes Reinecke 	unsigned char * arr;
122701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
12285a09e398SHannes Reinecke 	int alloc_len, n, ret;
1229c2248fc9SDouglas Gilbert 	bool have_wlun;
12301da177e4SLinus Torvalds 
12311da177e4SLinus Torvalds 	alloc_len = (cmd[3] << 8) + cmd[4];
12326f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
12336f3cbf55SDouglas Gilbert 	if (! arr)
12346f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
1235c2248fc9SDouglas Gilbert 	have_wlun = (scp->device->lun == SAM2_WLUN_REPORT_LUNS);
1236c2248fc9SDouglas Gilbert 	if (have_wlun)
1237c65b1445SDouglas Gilbert 		pq_pdt = 0x1e;	/* present, wlun */
1238c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (0 == devip->lun))
1239c65b1445SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, no device type */
1240c65b1445SDouglas Gilbert 	else
12411da177e4SLinus Torvalds 		pq_pdt = (scsi_debug_ptype & 0x1f);
12421da177e4SLinus Torvalds 	arr[0] = pq_pdt;
12431da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
124422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
12455a09e398SHannes Reinecke 		kfree(arr);
12461da177e4SLinus Torvalds 		return check_condition_result;
12471da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
12485a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1249c65b1445SDouglas Gilbert 		char lu_id_str[6];
1250c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
12511da177e4SLinus Torvalds 
12525a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
12535a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
125423183910SDouglas Gilbert 		if (0 == scsi_debug_vpd_use_hostno)
125523183910SDouglas Gilbert 			host_no = 0;
1256c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1257c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1258c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1259c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1260c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
12611da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1262c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1263c65b1445SDouglas Gilbert 			n = 4;
1264c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1265c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1266c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1267c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1268c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1269c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1270c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1271c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1272c65b1445SDouglas Gilbert 			arr[n++] = 0x89;  /* ATA information */
1273c65b1445SDouglas Gilbert 			arr[n++] = 0xb0;  /* Block limits (SBC) */
1274eac6e8e4SMatthew Wilcox 			arr[n++] = 0xb1;  /* Block characteristics (SBC) */
12755b94e232SMartin K. Petersen 			if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
12765b94e232SMartin K. Petersen 				arr[n++] = 0xb2;
1277c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
12781da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1279c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
12801da177e4SLinus Torvalds 			arr[3] = len;
1281c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
12821da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1283c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
12845a09e398SHannes Reinecke 			arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
12855a09e398SHannes Reinecke 						 target_dev_id, lu_id_num,
12865a09e398SHannes Reinecke 						 lu_id_str, len);
1287c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1288c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1289c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_84(&arr[4]);
1290c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1291c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1292c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_85(&arr[4]);
1293c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1294c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1295c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
1296c6a44287SMartin K. Petersen 			if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
1297c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1298c6a44287SMartin K. Petersen 			else if (scsi_debug_dif)
1299c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1300c6a44287SMartin K. Petersen 			else
1301c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1302c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1303c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1304c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1305c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1306c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1307c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1308c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1309c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1310c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1311c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1312c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1313c65b1445SDouglas Gilbert 		} else if (0x89 == cmd[2]) { /* ATA information */
1314c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1315c65b1445SDouglas Gilbert 			n = inquiry_evpd_89(&arr[4]);
1316c65b1445SDouglas Gilbert 			arr[2] = (n >> 8);
1317c65b1445SDouglas Gilbert 			arr[3] = (n & 0xff);
1318c65b1445SDouglas Gilbert 		} else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1319c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1320c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_b0(&arr[4]);
1321eac6e8e4SMatthew Wilcox 		} else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
1322eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
1323eac6e8e4SMatthew Wilcox 			arr[3] = inquiry_evpd_b1(&arr[4]);
13245b94e232SMartin K. Petersen 		} else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
13256014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
13266014759cSMartin K. Petersen 			arr[3] = inquiry_evpd_b2(&arr[4]);
13271da177e4SLinus Torvalds 		} else {
132822017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
13295a09e398SHannes Reinecke 			kfree(arr);
13301da177e4SLinus Torvalds 			return check_condition_result;
13311da177e4SLinus Torvalds 		}
1332c65b1445SDouglas Gilbert 		len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
13335a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1334c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
13355a09e398SHannes Reinecke 		kfree(arr);
13365a09e398SHannes Reinecke 		return ret;
13371da177e4SLinus Torvalds 	}
13381da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1339d986788bSMartin Pitt 	arr[1] = scsi_debug_removable ? 0x80 : 0;	/* Removable disk */
13401da177e4SLinus Torvalds 	arr[2] = scsi_debug_scsi_level;
13411da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
13421da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1343c6a44287SMartin K. Petersen 	arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
13445a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno)
13455a09e398SHannes Reinecke 		arr[5] = 0x10; /* claim: implicit TGPS */
1346c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
13471da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1348c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
13491da177e4SLinus Torvalds 	memcpy(&arr[8], inq_vendor_id, 8);
13501da177e4SLinus Torvalds 	memcpy(&arr[16], inq_product_id, 16);
13511da177e4SLinus Torvalds 	memcpy(&arr[32], inq_product_rev, 4);
13521da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1353e46b0344SDouglas Gilbert 	arr[58] = 0x0; arr[59] = 0xa2;  /* SAM-5 rev 4 */
1354e46b0344SDouglas Gilbert 	arr[60] = 0x4; arr[61] = 0x68;  /* SPC-4 rev 37 */
1355c65b1445SDouglas Gilbert 	n = 62;
13561da177e4SLinus Torvalds 	if (scsi_debug_ptype == 0) {
1357e46b0344SDouglas Gilbert 		arr[n++] = 0x4; arr[n++] = 0xc5; /* SBC-4 rev 36 */
13581da177e4SLinus Torvalds 	} else if (scsi_debug_ptype == 1) {
1359e46b0344SDouglas Gilbert 		arr[n++] = 0x5; arr[n++] = 0x25; /* SSC-4 rev 3 */
13601da177e4SLinus Torvalds 	}
1361e46b0344SDouglas Gilbert 	arr[n++] = 0x20; arr[n++] = 0xe6;  /* SPL-3 rev 7 */
13625a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
13631da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
13645a09e398SHannes Reinecke 	kfree(arr);
13655a09e398SHannes Reinecke 	return ret;
13661da177e4SLinus Torvalds }
13671da177e4SLinus Torvalds 
13681da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp,
13691da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip)
13701da177e4SLinus Torvalds {
13711da177e4SLinus Torvalds 	unsigned char * sbuff;
137201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1373cbf67842SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
1374c2248fc9SDouglas Gilbert 	bool dsense, want_dsense;
13751da177e4SLinus Torvalds 	int len = 18;
13761da177e4SLinus Torvalds 
1377c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1378c2248fc9SDouglas Gilbert 	dsense = !!(cmd[1] & 1);
1379c2248fc9SDouglas Gilbert 	want_dsense = dsense || scsi_debug_dsense;
1380cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
1381c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1382c2248fc9SDouglas Gilbert 		if (dsense) {
1383c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1384c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1385c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
1386c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
1387c2248fc9SDouglas Gilbert 			len = 8;
1388c65b1445SDouglas Gilbert 		} else {
1389c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1390c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1391c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1392c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
1393c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
1394c65b1445SDouglas Gilbert 		}
1395c65b1445SDouglas Gilbert 	} else {
1396cbf67842SDouglas Gilbert 		memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
1397c2248fc9SDouglas Gilbert 		if (arr[0] >= 0x70 && dsense == scsi_debug_dsense)
1398c2248fc9SDouglas Gilbert 			;	/* have sense and formats match */
1399c2248fc9SDouglas Gilbert 		else if (arr[0] <= 0x70) {
1400c2248fc9SDouglas Gilbert 			if (dsense) {
1401c2248fc9SDouglas Gilbert 				memset(arr, 0, 8);
1402c2248fc9SDouglas Gilbert 				arr[0] = 0x72;
1403c2248fc9SDouglas Gilbert 				len = 8;
1404c2248fc9SDouglas Gilbert 			} else {
1405c2248fc9SDouglas Gilbert 				memset(arr, 0, 18);
1406c2248fc9SDouglas Gilbert 				arr[0] = 0x70;
1407c2248fc9SDouglas Gilbert 				arr[7] = 0xa;
1408c2248fc9SDouglas Gilbert 			}
1409c2248fc9SDouglas Gilbert 		} else if (dsense) {
1410c2248fc9SDouglas Gilbert 			memset(arr, 0, 8);
14111da177e4SLinus Torvalds 			arr[0] = 0x72;
14121da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
14131da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
14141da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
14151da177e4SLinus Torvalds 			len = 8;
1416c2248fc9SDouglas Gilbert 		} else {
1417c2248fc9SDouglas Gilbert 			memset(arr, 0, 18);
1418c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1419c2248fc9SDouglas Gilbert 			arr[2] = sbuff[1];
1420c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1421c2248fc9SDouglas Gilbert 			arr[12] = sbuff[1];
1422c2248fc9SDouglas Gilbert 			arr[13] = sbuff[3];
1423c65b1445SDouglas Gilbert 		}
1424c2248fc9SDouglas Gilbert 
1425c65b1445SDouglas Gilbert 	}
1426cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
14271da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
14281da177e4SLinus Torvalds }
14291da177e4SLinus Torvalds 
1430c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp,
1431c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
1432c65b1445SDouglas Gilbert {
143301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1434c2248fc9SDouglas Gilbert 	int power_cond, start;
1435c65b1445SDouglas Gilbert 
1436c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1437c65b1445SDouglas Gilbert 	if (power_cond) {
143822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1439c65b1445SDouglas Gilbert 		return check_condition_result;
1440c65b1445SDouglas Gilbert 	}
1441c65b1445SDouglas Gilbert 	start = cmd[4] & 1;
1442c65b1445SDouglas Gilbert 	if (start == devip->stopped)
1443c65b1445SDouglas Gilbert 		devip->stopped = !start;
1444c65b1445SDouglas Gilbert 	return 0;
1445c65b1445SDouglas Gilbert }
1446c65b1445SDouglas Gilbert 
144728898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
144828898873SFUJITA Tomonori {
144928898873SFUJITA Tomonori 	if (scsi_debug_virtual_gb > 0)
14505447ed6cSDouglas Gilbert 		return (sector_t)scsi_debug_virtual_gb *
14515447ed6cSDouglas Gilbert 			(1073741824 / scsi_debug_sector_size);
145228898873SFUJITA Tomonori 	else
145328898873SFUJITA Tomonori 		return sdebug_store_sectors;
145428898873SFUJITA Tomonori }
145528898873SFUJITA Tomonori 
14561da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
14571da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp,
14581da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
14591da177e4SLinus Torvalds {
14601da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1461c65b1445SDouglas Gilbert 	unsigned int capac;
14621da177e4SLinus Torvalds 
1463c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
146428898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
14651da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1466c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1467c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
14681da177e4SLinus Torvalds 		arr[0] = (capac >> 24);
14691da177e4SLinus Torvalds 		arr[1] = (capac >> 16) & 0xff;
14701da177e4SLinus Torvalds 		arr[2] = (capac >> 8) & 0xff;
14711da177e4SLinus Torvalds 		arr[3] = capac & 0xff;
1472c65b1445SDouglas Gilbert 	} else {
1473c65b1445SDouglas Gilbert 		arr[0] = 0xff;
1474c65b1445SDouglas Gilbert 		arr[1] = 0xff;
1475c65b1445SDouglas Gilbert 		arr[2] = 0xff;
1476c65b1445SDouglas Gilbert 		arr[3] = 0xff;
1477c65b1445SDouglas Gilbert 	}
1478597136abSMartin K. Petersen 	arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
1479597136abSMartin K. Petersen 	arr[7] = scsi_debug_sector_size & 0xff;
14801da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
14811da177e4SLinus Torvalds }
14821da177e4SLinus Torvalds 
1483c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1484c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp,
1485c65b1445SDouglas Gilbert 			  struct sdebug_dev_info * devip)
1486c65b1445SDouglas Gilbert {
148701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1488c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1489c65b1445SDouglas Gilbert 	unsigned long long capac;
1490c2248fc9SDouglas Gilbert 	int k, alloc_len;
1491c65b1445SDouglas Gilbert 
1492c65b1445SDouglas Gilbert 	alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1493c65b1445SDouglas Gilbert 		     + cmd[13]);
1494c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
149528898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1496c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1497c65b1445SDouglas Gilbert 	capac = sdebug_capacity - 1;
1498c65b1445SDouglas Gilbert 	for (k = 0; k < 8; ++k, capac >>= 8)
1499c65b1445SDouglas Gilbert 		arr[7 - k] = capac & 0xff;
1500597136abSMartin K. Petersen 	arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
1501597136abSMartin K. Petersen 	arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
1502597136abSMartin K. Petersen 	arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
1503597136abSMartin K. Petersen 	arr[11] = scsi_debug_sector_size & 0xff;
1504ea61fca5SMartin K. Petersen 	arr[13] = scsi_debug_physblk_exp & 0xf;
1505ea61fca5SMartin K. Petersen 	arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
150644d92694SMartin K. Petersen 
1507be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
15085b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1509be1dd78dSEric Sandeen 		if (scsi_debug_lbprz)
1510be1dd78dSEric Sandeen 			arr[14] |= 0x40; /* LBPRZ */
1511be1dd78dSEric Sandeen 	}
151244d92694SMartin K. Petersen 
1513ea61fca5SMartin K. Petersen 	arr[15] = scsi_debug_lowest_aligned & 0xff;
1514c6a44287SMartin K. Petersen 
1515c6a44287SMartin K. Petersen 	if (scsi_debug_dif) {
1516c6a44287SMartin K. Petersen 		arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
1517c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1518c6a44287SMartin K. Petersen 	}
1519c6a44287SMartin K. Petersen 
1520c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1521c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1522c65b1445SDouglas Gilbert }
1523c65b1445SDouglas Gilbert 
15245a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
15255a09e398SHannes Reinecke 
15265a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp,
15275a09e398SHannes Reinecke 			      struct sdebug_dev_info * devip)
15285a09e398SHannes Reinecke {
152901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
15305a09e398SHannes Reinecke 	unsigned char * arr;
15315a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
15325a09e398SHannes Reinecke 	int n, ret, alen, rlen;
15335a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
15345a09e398SHannes Reinecke 
15355a09e398SHannes Reinecke 	alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
15365a09e398SHannes Reinecke 		+ cmd[9]);
15375a09e398SHannes Reinecke 
15386f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
15396f3cbf55SDouglas Gilbert 	if (! arr)
15406f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
15415a09e398SHannes Reinecke 	/*
15425a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
15435a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
15445a09e398SHannes Reinecke 	 * So we create two port groups with one port each
15455a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
15465a09e398SHannes Reinecke 	 */
15475a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
15485a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
15495a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
15505a09e398SHannes Reinecke 	    (devip->channel & 0x7f);
15515a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
15525a09e398SHannes Reinecke 	    (devip->channel & 0x7f) + 0x80;
15535a09e398SHannes Reinecke 
15545a09e398SHannes Reinecke 	/*
15555a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
15565a09e398SHannes Reinecke 	 */
15575a09e398SHannes Reinecke 	n = 4;
15585a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno) {
15595a09e398SHannes Reinecke 	    arr[n++] = host_no % 3; /* Asymm access state */
15605a09e398SHannes Reinecke 	    arr[n++] = 0x0F; /* claim: all states are supported */
15615a09e398SHannes Reinecke 	} else {
15625a09e398SHannes Reinecke 	    arr[n++] = 0x0; /* Active/Optimized path */
15635a09e398SHannes Reinecke 	    arr[n++] = 0x01; /* claim: only support active/optimized paths */
15645a09e398SHannes Reinecke 	}
15655a09e398SHannes Reinecke 	arr[n++] = (port_group_a >> 8) & 0xff;
15665a09e398SHannes Reinecke 	arr[n++] = port_group_a & 0xff;
15675a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
15685a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
15695a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
15705a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
15715a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
15725a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
15735a09e398SHannes Reinecke 	arr[n++] = (port_a >> 8) & 0xff;
15745a09e398SHannes Reinecke 	arr[n++] = port_a & 0xff;
15755a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
15765a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
15775a09e398SHannes Reinecke 	arr[n++] = (port_group_b >> 8) & 0xff;
15785a09e398SHannes Reinecke 	arr[n++] = port_group_b & 0xff;
15795a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
15805a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
15815a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
15825a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
15835a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
15845a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
15855a09e398SHannes Reinecke 	arr[n++] = (port_b >> 8) & 0xff;
15865a09e398SHannes Reinecke 	arr[n++] = port_b & 0xff;
15875a09e398SHannes Reinecke 
15885a09e398SHannes Reinecke 	rlen = n - 4;
15895a09e398SHannes Reinecke 	arr[0] = (rlen >> 24) & 0xff;
15905a09e398SHannes Reinecke 	arr[1] = (rlen >> 16) & 0xff;
15915a09e398SHannes Reinecke 	arr[2] = (rlen >> 8) & 0xff;
15925a09e398SHannes Reinecke 	arr[3] = rlen & 0xff;
15935a09e398SHannes Reinecke 
15945a09e398SHannes Reinecke 	/*
15955a09e398SHannes Reinecke 	 * Return the smallest value of either
15965a09e398SHannes Reinecke 	 * - The allocated length
15975a09e398SHannes Reinecke 	 * - The constructed command length
15985a09e398SHannes Reinecke 	 * - The maximum array size
15995a09e398SHannes Reinecke 	 */
16005a09e398SHannes Reinecke 	rlen = min(alen,n);
16015a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
16025a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
16035a09e398SHannes Reinecke 	kfree(arr);
16045a09e398SHannes Reinecke 	return ret;
16055a09e398SHannes Reinecke }
16065a09e398SHannes Reinecke 
160738d5c833SDouglas Gilbert static int
160838d5c833SDouglas Gilbert resp_rsup_opcodes(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
160938d5c833SDouglas Gilbert {
161038d5c833SDouglas Gilbert 	bool rctd;
161138d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
161238d5c833SDouglas Gilbert 	u16 req_sa, u;
161338d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
161438d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
161538d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
161638d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
161738d5c833SDouglas Gilbert 	u8 *arr;
161838d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
161938d5c833SDouglas Gilbert 
162038d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
162138d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
162238d5c833SDouglas Gilbert 	req_opcode = cmd[3];
162338d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
162438d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
162538d5c833SDouglas Gilbert 	if (alloc_len < 4 && alloc_len > 0xffff) {
162638d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
162738d5c833SDouglas Gilbert 		return check_condition_result;
162838d5c833SDouglas Gilbert 	}
162938d5c833SDouglas Gilbert 	if (alloc_len > 8192)
163038d5c833SDouglas Gilbert 		a_len = 8192;
163138d5c833SDouglas Gilbert 	else
163238d5c833SDouglas Gilbert 		a_len = alloc_len;
163338d5c833SDouglas Gilbert 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_KERNEL);
163438d5c833SDouglas Gilbert 	if (NULL == arr) {
163538d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
163638d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
163738d5c833SDouglas Gilbert 		return check_condition_result;
163838d5c833SDouglas Gilbert 	}
163938d5c833SDouglas Gilbert 	switch (reporting_opts) {
164038d5c833SDouglas Gilbert 	case 0:	/* all commands */
164138d5c833SDouglas Gilbert 		/* count number of commands */
164238d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
164338d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
164438d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
164538d5c833SDouglas Gilbert 				continue;
164638d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
164738d5c833SDouglas Gilbert 		}
164838d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
164938d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
165038d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
165138d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
165238d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
165338d5c833SDouglas Gilbert 				continue;
165438d5c833SDouglas Gilbert 			na = oip->num_attached;
165538d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
165638d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
165738d5c833SDouglas Gilbert 			if (rctd)
165838d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
165938d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
166038d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
166138d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
166238d5c833SDouglas Gilbert 			if (rctd)
166338d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
166438d5c833SDouglas Gilbert 			r_oip = oip;
166538d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
166638d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
166738d5c833SDouglas Gilbert 					continue;
166838d5c833SDouglas Gilbert 				offset += bump;
166938d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
167038d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
167138d5c833SDouglas Gilbert 				if (rctd)
167238d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
167338d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
167438d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
167538d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
167638d5c833SDouglas Gilbert 						   arr + offset + 6);
167738d5c833SDouglas Gilbert 				if (rctd)
167838d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
167938d5c833SDouglas Gilbert 							   arr + offset + 8);
168038d5c833SDouglas Gilbert 			}
168138d5c833SDouglas Gilbert 			oip = r_oip;
168238d5c833SDouglas Gilbert 			offset += bump;
168338d5c833SDouglas Gilbert 		}
168438d5c833SDouglas Gilbert 		break;
168538d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
168638d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
168738d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
168838d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
168938d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
169038d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
169138d5c833SDouglas Gilbert 			supp = 1;
169238d5c833SDouglas Gilbert 			offset = 4;
169338d5c833SDouglas Gilbert 		} else {
169438d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
169538d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
169638d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
169738d5c833SDouglas Gilbert 							     2, 2);
169838d5c833SDouglas Gilbert 					kfree(arr);
169938d5c833SDouglas Gilbert 					return check_condition_result;
170038d5c833SDouglas Gilbert 				}
170138d5c833SDouglas Gilbert 				req_sa = 0;
170238d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
170338d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
170438d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
170538d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
170638d5c833SDouglas Gilbert 				return check_condition_result;
170738d5c833SDouglas Gilbert 			}
170838d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
170938d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
171038d5c833SDouglas Gilbert 				supp = 3;
171138d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
171238d5c833SDouglas Gilbert 				na = oip->num_attached;
171338d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
171438d5c833SDouglas Gilbert 				     ++k, ++oip) {
171538d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
171638d5c833SDouglas Gilbert 						break;
171738d5c833SDouglas Gilbert 				}
171838d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
171938d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
172038d5c833SDouglas Gilbert 				na = oip->num_attached;
172138d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
172238d5c833SDouglas Gilbert 				     ++k, ++oip) {
172338d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
172438d5c833SDouglas Gilbert 						break;
172538d5c833SDouglas Gilbert 				}
172638d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
172738d5c833SDouglas Gilbert 			} else
172838d5c833SDouglas Gilbert 				supp = 3;
172938d5c833SDouglas Gilbert 			if (3 == supp) {
173038d5c833SDouglas Gilbert 				u = oip->len_mask[0];
173138d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
173238d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
173338d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
173438d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
173538d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
173638d5c833SDouglas Gilbert 				offset = 4 + u;
173738d5c833SDouglas Gilbert 			} else
173838d5c833SDouglas Gilbert 				offset = 4;
173938d5c833SDouglas Gilbert 		}
174038d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
174138d5c833SDouglas Gilbert 		if (rctd) {
174238d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
174338d5c833SDouglas Gilbert 			offset += 12;
174438d5c833SDouglas Gilbert 		}
174538d5c833SDouglas Gilbert 		break;
174638d5c833SDouglas Gilbert 	default:
174738d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
174838d5c833SDouglas Gilbert 		kfree(arr);
174938d5c833SDouglas Gilbert 		return check_condition_result;
175038d5c833SDouglas Gilbert 	}
175138d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
175238d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
175338d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
175438d5c833SDouglas Gilbert 	kfree(arr);
175538d5c833SDouglas Gilbert 	return errsts;
175638d5c833SDouglas Gilbert }
175738d5c833SDouglas Gilbert 
175838d5c833SDouglas Gilbert static int
175938d5c833SDouglas Gilbert resp_rsup_tmfs(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
176038d5c833SDouglas Gilbert {
176138d5c833SDouglas Gilbert 	bool repd;
176238d5c833SDouglas Gilbert 	u32 alloc_len, len;
176338d5c833SDouglas Gilbert 	u8 arr[16];
176438d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
176538d5c833SDouglas Gilbert 
176638d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
176738d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
176838d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
176938d5c833SDouglas Gilbert 	if (alloc_len < 4) {
177038d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
177138d5c833SDouglas Gilbert 		return check_condition_result;
177238d5c833SDouglas Gilbert 	}
177338d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
177438d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
177538d5c833SDouglas Gilbert 	if (repd) {
177638d5c833SDouglas Gilbert 		arr[3] = 0xc;
177738d5c833SDouglas Gilbert 		len = 16;
177838d5c833SDouglas Gilbert 	} else
177938d5c833SDouglas Gilbert 		len = 4;
178038d5c833SDouglas Gilbert 
178138d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
178238d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
178338d5c833SDouglas Gilbert }
178438d5c833SDouglas Gilbert 
17851da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
17861da177e4SLinus Torvalds 
17871da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
17881da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
17891da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
17901da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
17911da177e4SLinus Torvalds 
17921da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
17931da177e4SLinus Torvalds 	if (1 == pcontrol)
17941da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
17951da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
17961da177e4SLinus Torvalds }
17971da177e4SLinus Torvalds 
17981da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
17991da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
18001da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
18011da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
18021da177e4SLinus Torvalds 
18031da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
18041da177e4SLinus Torvalds 	if (1 == pcontrol)
18051da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
18061da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
18071da177e4SLinus Torvalds }
18081da177e4SLinus Torvalds 
18091da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target)
18101da177e4SLinus Torvalds {       /* Format device page for mode_sense */
18111da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
18121da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
18131da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
18141da177e4SLinus Torvalds 
18151da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
18161da177e4SLinus Torvalds 	p[10] = (sdebug_sectors_per >> 8) & 0xff;
18171da177e4SLinus Torvalds 	p[11] = sdebug_sectors_per & 0xff;
1818597136abSMartin K. Petersen 	p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1819597136abSMartin K. Petersen 	p[13] = scsi_debug_sector_size & 0xff;
1820d986788bSMartin Pitt 	if (scsi_debug_removable)
18211da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
18221da177e4SLinus Torvalds 	if (1 == pcontrol)
18231da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
18241da177e4SLinus Torvalds 	return sizeof(format_pg);
18251da177e4SLinus Torvalds }
18261da177e4SLinus Torvalds 
18271da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
18281da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
1829cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1830cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1831cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
18321da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
18331da177e4SLinus Torvalds 
1834cbf67842SDouglas Gilbert 	if (SCSI_DEBUG_OPT_N_WCE & scsi_debug_opts)
1835cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
18361da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
18371da177e4SLinus Torvalds 	if (1 == pcontrol)
1838cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1839cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
1840cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
18411da177e4SLinus Torvalds 	return sizeof(caching_pg);
18421da177e4SLinus Torvalds }
18431da177e4SLinus Torvalds 
18441da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
18451da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
1846c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1847c65b1445SDouglas Gilbert 				        0, 0, 0, 0};
1848c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
18491da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
18501da177e4SLinus Torvalds 
18511da177e4SLinus Torvalds 	if (scsi_debug_dsense)
18521da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
1853c65b1445SDouglas Gilbert 	else
1854c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
1855c6a44287SMartin K. Petersen 
1856c6a44287SMartin K. Petersen 	if (scsi_debug_ato)
1857c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1858c6a44287SMartin K. Petersen 
18591da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
18601da177e4SLinus Torvalds 	if (1 == pcontrol)
1861c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1862c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1863c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
18641da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
18651da177e4SLinus Torvalds }
18661da177e4SLinus Torvalds 
1867c65b1445SDouglas Gilbert 
18681da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
18691da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
1870c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
18711da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
1872c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1873c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
1874c65b1445SDouglas Gilbert 
18751da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
18761da177e4SLinus Torvalds 	if (1 == pcontrol)
1877c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1878c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1879c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
18801da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
18811da177e4SLinus Torvalds }
18821da177e4SLinus Torvalds 
1883c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1884c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
1885c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1886c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1887c65b1445SDouglas Gilbert 
1888c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1889c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1890c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1891c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
1892c65b1445SDouglas Gilbert }
1893c65b1445SDouglas Gilbert 
1894c65b1445SDouglas Gilbert 
1895c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1896c65b1445SDouglas Gilbert 			      int target_dev_id)
1897c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
1898c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1899c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1900c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1901c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1902c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
1903c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1904c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1905c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1906c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1907c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1908c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
1909c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1910c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1911c65b1445SDouglas Gilbert 		};
1912c65b1445SDouglas Gilbert 	int port_a, port_b;
1913c65b1445SDouglas Gilbert 
1914c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1915c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1916c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1917c65b1445SDouglas Gilbert 	p[20] = (port_a >> 24);
1918c65b1445SDouglas Gilbert 	p[21] = (port_a >> 16) & 0xff;
1919c65b1445SDouglas Gilbert 	p[22] = (port_a >> 8) & 0xff;
1920c65b1445SDouglas Gilbert 	p[23] = port_a & 0xff;
1921c65b1445SDouglas Gilbert 	p[48 + 20] = (port_b >> 24);
1922c65b1445SDouglas Gilbert 	p[48 + 21] = (port_b >> 16) & 0xff;
1923c65b1445SDouglas Gilbert 	p[48 + 22] = (port_b >> 8) & 0xff;
1924c65b1445SDouglas Gilbert 	p[48 + 23] = port_b & 0xff;
1925c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1926c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1927c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
1928c65b1445SDouglas Gilbert }
1929c65b1445SDouglas Gilbert 
1930c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1931c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
1932c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1933c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1934c65b1445SDouglas Gilbert 		};
1935c65b1445SDouglas Gilbert 
1936c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1937c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1938c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1939c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
1940c65b1445SDouglas Gilbert }
1941c65b1445SDouglas Gilbert 
19421da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
19431da177e4SLinus Torvalds 
1944c2248fc9SDouglas Gilbert static int
1945c2248fc9SDouglas Gilbert resp_mode_sense(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
19461da177e4SLinus Torvalds {
194723183910SDouglas Gilbert 	unsigned char dbd, llbaa;
194823183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
19491da177e4SLinus Torvalds 	unsigned char dev_spec;
1950c2248fc9SDouglas Gilbert 	int k, alloc_len, msense_6, offset, len, target_dev_id;
1951c2248fc9SDouglas Gilbert 	int target = scp->device->id;
19521da177e4SLinus Torvalds 	unsigned char * ap;
19531da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
195401123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
19551da177e4SLinus Torvalds 
195623183910SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);
19571da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
19581da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
19591da177e4SLinus Torvalds 	subpcode = cmd[3];
19601da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
196123183910SDouglas Gilbert 	llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
196223183910SDouglas Gilbert 	if ((0 == scsi_debug_ptype) && (0 == dbd))
196323183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
196423183910SDouglas Gilbert 	else
196523183910SDouglas Gilbert 		bd_len = 0;
19661da177e4SLinus Torvalds 	alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
19671da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
19681da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
1969cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
19701da177e4SLinus Torvalds 		return check_condition_result;
19711da177e4SLinus Torvalds 	}
1972c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1973c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
197423183910SDouglas Gilbert 	/* set DPOFUA bit for disks */
197523183910SDouglas Gilbert 	if (0 == scsi_debug_ptype)
197623183910SDouglas Gilbert 		dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
197723183910SDouglas Gilbert 	else
197823183910SDouglas Gilbert 		dev_spec = 0x0;
19791da177e4SLinus Torvalds 	if (msense_6) {
19801da177e4SLinus Torvalds 		arr[2] = dev_spec;
198123183910SDouglas Gilbert 		arr[3] = bd_len;
19821da177e4SLinus Torvalds 		offset = 4;
19831da177e4SLinus Torvalds 	} else {
19841da177e4SLinus Torvalds 		arr[3] = dev_spec;
198523183910SDouglas Gilbert 		if (16 == bd_len)
198623183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
198723183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
19881da177e4SLinus Torvalds 		offset = 8;
19891da177e4SLinus Torvalds 	}
19901da177e4SLinus Torvalds 	ap = arr + offset;
199128898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
199228898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
199328898873SFUJITA Tomonori 
199423183910SDouglas Gilbert 	if (8 == bd_len) {
199523183910SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe) {
199623183910SDouglas Gilbert 			ap[0] = 0xff;
199723183910SDouglas Gilbert 			ap[1] = 0xff;
199823183910SDouglas Gilbert 			ap[2] = 0xff;
199923183910SDouglas Gilbert 			ap[3] = 0xff;
200023183910SDouglas Gilbert 		} else {
200123183910SDouglas Gilbert 			ap[0] = (sdebug_capacity >> 24) & 0xff;
200223183910SDouglas Gilbert 			ap[1] = (sdebug_capacity >> 16) & 0xff;
200323183910SDouglas Gilbert 			ap[2] = (sdebug_capacity >> 8) & 0xff;
200423183910SDouglas Gilbert 			ap[3] = sdebug_capacity & 0xff;
200523183910SDouglas Gilbert 		}
2006597136abSMartin K. Petersen 		ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
2007597136abSMartin K. Petersen 		ap[7] = scsi_debug_sector_size & 0xff;
200823183910SDouglas Gilbert 		offset += bd_len;
200923183910SDouglas Gilbert 		ap = arr + offset;
201023183910SDouglas Gilbert 	} else if (16 == bd_len) {
201123183910SDouglas Gilbert 		unsigned long long capac = sdebug_capacity;
201223183910SDouglas Gilbert 
201323183910SDouglas Gilbert         	for (k = 0; k < 8; ++k, capac >>= 8)
201423183910SDouglas Gilbert                 	ap[7 - k] = capac & 0xff;
2015597136abSMartin K. Petersen 		ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
2016597136abSMartin K. Petersen 		ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
2017597136abSMartin K. Petersen 		ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
2018597136abSMartin K. Petersen 		ap[15] = scsi_debug_sector_size & 0xff;
201923183910SDouglas Gilbert 		offset += bd_len;
202023183910SDouglas Gilbert 		ap = arr + offset;
202123183910SDouglas Gilbert 	}
20221da177e4SLinus Torvalds 
2023c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2024c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
202522017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
20261da177e4SLinus Torvalds 		return check_condition_result;
20271da177e4SLinus Torvalds 	}
20281da177e4SLinus Torvalds 	switch (pcode) {
20291da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
20301da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
20311da177e4SLinus Torvalds 		offset += len;
20321da177e4SLinus Torvalds 		break;
20331da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
20341da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
20351da177e4SLinus Torvalds 		offset += len;
20361da177e4SLinus Torvalds 		break;
20371da177e4SLinus Torvalds         case 0x3:       /* Format device page, direct access */
20381da177e4SLinus Torvalds                 len = resp_format_pg(ap, pcontrol, target);
20391da177e4SLinus Torvalds                 offset += len;
20401da177e4SLinus Torvalds                 break;
20411da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
20421da177e4SLinus Torvalds 		len = resp_caching_pg(ap, pcontrol, target);
20431da177e4SLinus Torvalds 		offset += len;
20441da177e4SLinus Torvalds 		break;
20451da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
20461da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
20471da177e4SLinus Torvalds 		offset += len;
20481da177e4SLinus Torvalds 		break;
2049c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2050c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
205122017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2052c65b1445SDouglas Gilbert 			return check_condition_result;
2053c65b1445SDouglas Gilbert 	        }
2054c65b1445SDouglas Gilbert 		len = 0;
2055c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2056c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2057c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2058c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2059c65b1445SDouglas Gilbert 						  target_dev_id);
2060c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2061c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2062c65b1445SDouglas Gilbert 		offset += len;
2063c65b1445SDouglas Gilbert 		break;
20641da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
20651da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
20661da177e4SLinus Torvalds 		offset += len;
20671da177e4SLinus Torvalds 		break;
20681da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2069c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
20701da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
20711da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
20721da177e4SLinus Torvalds 			len += resp_format_pg(ap + len, pcontrol, target);
20731da177e4SLinus Torvalds 			len += resp_caching_pg(ap + len, pcontrol, target);
20741da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2075c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2076c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2077c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2078c65b1445SDouglas Gilbert 						  target, target_dev_id);
2079c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2080c65b1445SDouglas Gilbert 			}
20811da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2082c65b1445SDouglas Gilbert 		} else {
208322017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2084c65b1445SDouglas Gilbert 			return check_condition_result;
2085c65b1445SDouglas Gilbert                 }
20861da177e4SLinus Torvalds 		offset += len;
20871da177e4SLinus Torvalds 		break;
20881da177e4SLinus Torvalds 	default:
208922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
20901da177e4SLinus Torvalds 		return check_condition_result;
20911da177e4SLinus Torvalds 	}
20921da177e4SLinus Torvalds 	if (msense_6)
20931da177e4SLinus Torvalds 		arr[0] = offset - 1;
20941da177e4SLinus Torvalds 	else {
20951da177e4SLinus Torvalds 		arr[0] = ((offset - 2) >> 8) & 0xff;
20961da177e4SLinus Torvalds 		arr[1] = (offset - 2) & 0xff;
20971da177e4SLinus Torvalds 	}
20981da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
20991da177e4SLinus Torvalds }
21001da177e4SLinus Torvalds 
2101c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2102c65b1445SDouglas Gilbert 
2103c2248fc9SDouglas Gilbert static int
2104c2248fc9SDouglas Gilbert resp_mode_select(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
2105c65b1445SDouglas Gilbert {
2106c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2107c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2108c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
210901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2110c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2111c65b1445SDouglas Gilbert 
2112c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2113c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2114c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2115c65b1445SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
2116c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
211722017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2118c65b1445SDouglas Gilbert 		return check_condition_result;
2119c65b1445SDouglas Gilbert 	}
2120c65b1445SDouglas Gilbert         res = fetch_to_dev_buffer(scp, arr, param_len);
2121c65b1445SDouglas Gilbert         if (-1 == res)
2122c65b1445SDouglas Gilbert                 return (DID_ERROR << 16);
2123c65b1445SDouglas Gilbert         else if ((res < param_len) &&
2124c65b1445SDouglas Gilbert                  (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
2125cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2126cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2127cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2128c65b1445SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
2129c65b1445SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
213023183910SDouglas Gilbert 	if (md_len > 2) {
213122017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2132c65b1445SDouglas Gilbert 		return check_condition_result;
2133c65b1445SDouglas Gilbert 	}
2134c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2135c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2136c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2137c65b1445SDouglas Gilbert 	if (ps) {
213822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2139c65b1445SDouglas Gilbert 		return check_condition_result;
2140c65b1445SDouglas Gilbert 	}
2141c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2142c65b1445SDouglas Gilbert 	pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
2143c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2144c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2145cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2146c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2147c65b1445SDouglas Gilbert 		return check_condition_result;
2148c65b1445SDouglas Gilbert 	}
2149c65b1445SDouglas Gilbert 	switch (mpage) {
2150cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2151cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2152cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2153cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2154cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2155cbf67842SDouglas Gilbert 		}
2156cbf67842SDouglas Gilbert 		break;
2157c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2158c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2159c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2160c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
2161c65b1445SDouglas Gilbert 			scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
2162cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2163c65b1445SDouglas Gilbert 		}
2164c65b1445SDouglas Gilbert 		break;
2165c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2166c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2167c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2168c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2169cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2170c65b1445SDouglas Gilbert 		}
2171c65b1445SDouglas Gilbert 		break;
2172c65b1445SDouglas Gilbert 	default:
2173c65b1445SDouglas Gilbert 		break;
2174c65b1445SDouglas Gilbert 	}
217522017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2176c65b1445SDouglas Gilbert 	return check_condition_result;
2177cbf67842SDouglas Gilbert set_mode_changed_ua:
2178cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2179cbf67842SDouglas Gilbert 	return 0;
2180c65b1445SDouglas Gilbert }
2181c65b1445SDouglas Gilbert 
2182c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr)
2183c65b1445SDouglas Gilbert {
2184c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2185c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2186c65b1445SDouglas Gilbert 		};
2187c65b1445SDouglas Gilbert 
2188c65b1445SDouglas Gilbert         memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2189c65b1445SDouglas Gilbert         return sizeof(temp_l_pg);
2190c65b1445SDouglas Gilbert }
2191c65b1445SDouglas Gilbert 
2192c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr)
2193c65b1445SDouglas Gilbert {
2194c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2195c65b1445SDouglas Gilbert 		};
2196c65b1445SDouglas Gilbert 
2197c65b1445SDouglas Gilbert         memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2198c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2199c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2200c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2201c65b1445SDouglas Gilbert 	}
2202c65b1445SDouglas Gilbert         return sizeof(ie_l_pg);
2203c65b1445SDouglas Gilbert }
2204c65b1445SDouglas Gilbert 
2205c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2206c65b1445SDouglas Gilbert 
2207c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp,
2208c65b1445SDouglas Gilbert                           struct sdebug_dev_info * devip)
2209c65b1445SDouglas Gilbert {
2210c2248fc9SDouglas Gilbert 	int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n;
2211c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
221201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2213c65b1445SDouglas Gilbert 
2214c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2215c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2216c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2217c65b1445SDouglas Gilbert 	if (ppc || sp) {
221822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2219c65b1445SDouglas Gilbert 		return check_condition_result;
2220c65b1445SDouglas Gilbert 	}
2221c65b1445SDouglas Gilbert 	pcontrol = (cmd[2] & 0xc0) >> 6;
2222c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
222323183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2224c65b1445SDouglas Gilbert 	alloc_len = (cmd[7] << 8) + cmd[8];
2225c65b1445SDouglas Gilbert 	arr[0] = pcode;
222623183910SDouglas Gilbert 	if (0 == subpcode) {
2227c65b1445SDouglas Gilbert 		switch (pcode) {
2228c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2229c65b1445SDouglas Gilbert 			n = 4;
2230c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2231c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2232c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2233c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2234c65b1445SDouglas Gilbert 			break;
2235c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2236c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2237c65b1445SDouglas Gilbert 			break;
2238c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2239c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2240c65b1445SDouglas Gilbert 			break;
2241c65b1445SDouglas Gilbert 		default:
224222017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2243c65b1445SDouglas Gilbert 			return check_condition_result;
2244c65b1445SDouglas Gilbert 		}
224523183910SDouglas Gilbert 	} else if (0xff == subpcode) {
224623183910SDouglas Gilbert 		arr[0] |= 0x40;
224723183910SDouglas Gilbert 		arr[1] = subpcode;
224823183910SDouglas Gilbert 		switch (pcode) {
224923183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
225023183910SDouglas Gilbert 			n = 4;
225123183910SDouglas Gilbert 			arr[n++] = 0x0;
225223183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
225323183910SDouglas Gilbert 			arr[n++] = 0x0;
225423183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
225523183910SDouglas Gilbert 			arr[n++] = 0xd;
225623183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
225723183910SDouglas Gilbert 			arr[n++] = 0x2f;
225823183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
225923183910SDouglas Gilbert 			arr[3] = n - 4;
226023183910SDouglas Gilbert 			break;
226123183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
226223183910SDouglas Gilbert 			n = 4;
226323183910SDouglas Gilbert 			arr[n++] = 0xd;
226423183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
226523183910SDouglas Gilbert 			arr[3] = n - 4;
226623183910SDouglas Gilbert 			break;
226723183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
226823183910SDouglas Gilbert 			n = 4;
226923183910SDouglas Gilbert 			arr[n++] = 0x2f;
227023183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
227123183910SDouglas Gilbert 			arr[3] = n - 4;
227223183910SDouglas Gilbert 			break;
227323183910SDouglas Gilbert 		default:
227422017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
227523183910SDouglas Gilbert 			return check_condition_result;
227623183910SDouglas Gilbert 		}
227723183910SDouglas Gilbert 	} else {
227822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
227923183910SDouglas Gilbert 		return check_condition_result;
228023183910SDouglas Gilbert 	}
2281c65b1445SDouglas Gilbert 	len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
2282c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
2283c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
2284c65b1445SDouglas Gilbert }
2285c65b1445SDouglas Gilbert 
2286cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp,
228719789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
22881da177e4SLinus Torvalds {
2289c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
229022017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
22911da177e4SLinus Torvalds 		return check_condition_result;
22921da177e4SLinus Torvalds 	}
2293c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2294c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
229522017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2296cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2297c65b1445SDouglas Gilbert 		return check_condition_result;
2298c65b1445SDouglas Gilbert 	}
229919789100SFUJITA Tomonori 	return 0;
230019789100SFUJITA Tomonori }
230119789100SFUJITA Tomonori 
2302a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
2303c2248fc9SDouglas Gilbert static int
2304c2248fc9SDouglas Gilbert do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num, bool do_write)
230519789100SFUJITA Tomonori {
230619789100SFUJITA Tomonori 	int ret;
2307c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2308a4517511SAkinobu Mita 	struct scsi_data_buffer *sdb;
2309a4517511SAkinobu Mita 	enum dma_data_direction dir;
2310a4517511SAkinobu Mita 	size_t (*func)(struct scatterlist *, unsigned int, void *, size_t,
2311a4517511SAkinobu Mita 		       off_t);
231219789100SFUJITA Tomonori 
2313c2248fc9SDouglas Gilbert 	if (do_write) {
2314a4517511SAkinobu Mita 		sdb = scsi_out(scmd);
2315a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
2316a4517511SAkinobu Mita 		func = sg_pcopy_to_buffer;
2317a4517511SAkinobu Mita 	} else {
2318a4517511SAkinobu Mita 		sdb = scsi_in(scmd);
2319a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2320a4517511SAkinobu Mita 		func = sg_pcopy_from_buffer;
2321a4517511SAkinobu Mita 	}
2322a4517511SAkinobu Mita 
2323a4517511SAkinobu Mita 	if (!sdb->length)
2324a4517511SAkinobu Mita 		return 0;
2325a4517511SAkinobu Mita 	if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2326a4517511SAkinobu Mita 		return -1;
232719789100SFUJITA Tomonori 
232819789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
232919789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
233019789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
233119789100SFUJITA Tomonori 
2332a4517511SAkinobu Mita 	ret = func(sdb->table.sgl, sdb->table.nents,
2333a4517511SAkinobu Mita 		   fake_storep + (block * scsi_debug_sector_size),
2334a4517511SAkinobu Mita 		   (num - rest) * scsi_debug_sector_size, 0);
2335a4517511SAkinobu Mita 	if (ret != (num - rest) * scsi_debug_sector_size)
2336a4517511SAkinobu Mita 		return ret;
2337a4517511SAkinobu Mita 
2338a4517511SAkinobu Mita 	if (rest) {
2339a4517511SAkinobu Mita 		ret += func(sdb->table.sgl, sdb->table.nents,
2340a4517511SAkinobu Mita 			    fake_storep, rest * scsi_debug_sector_size,
2341597136abSMartin K. Petersen 			    (num - rest) * scsi_debug_sector_size);
2342a4517511SAkinobu Mita 	}
234319789100SFUJITA Tomonori 
234419789100SFUJITA Tomonori 	return ret;
234519789100SFUJITA Tomonori }
234619789100SFUJITA Tomonori 
234738d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of
234838d5c833SDouglas Gilbert  * arr into fake_store(lba,num) and return true. If comparison fails then
234938d5c833SDouglas Gilbert  * return false. */
235038d5c833SDouglas Gilbert static bool
235138d5c833SDouglas Gilbert comp_write_worker(u64 lba, u32 num, const u8 *arr)
235238d5c833SDouglas Gilbert {
235338d5c833SDouglas Gilbert 	bool res;
235438d5c833SDouglas Gilbert 	u64 block, rest = 0;
235538d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
235638d5c833SDouglas Gilbert 	u32 lb_size = scsi_debug_sector_size;
235738d5c833SDouglas Gilbert 
235838d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
235938d5c833SDouglas Gilbert 	if (block + num > store_blks)
236038d5c833SDouglas Gilbert 		rest = block + num - store_blks;
236138d5c833SDouglas Gilbert 
236238d5c833SDouglas Gilbert 	res = !memcmp(fake_storep + (block * lb_size), arr,
236338d5c833SDouglas Gilbert 		      (num - rest) * lb_size);
236438d5c833SDouglas Gilbert 	if (!res)
236538d5c833SDouglas Gilbert 		return res;
236638d5c833SDouglas Gilbert 	if (rest)
236738d5c833SDouglas Gilbert 		res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
236838d5c833SDouglas Gilbert 			     rest * lb_size);
236938d5c833SDouglas Gilbert 	if (!res)
237038d5c833SDouglas Gilbert 		return res;
237138d5c833SDouglas Gilbert 	arr += num * lb_size;
237238d5c833SDouglas Gilbert 	memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
237338d5c833SDouglas Gilbert 	if (rest)
237438d5c833SDouglas Gilbert 		memcpy(fake_storep, arr + ((num - rest) * lb_size),
237538d5c833SDouglas Gilbert 		       rest * lb_size);
237638d5c833SDouglas Gilbert 	return res;
237738d5c833SDouglas Gilbert }
237838d5c833SDouglas Gilbert 
237951d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2380beb40ea4SAkinobu Mita {
238151d648afSAkinobu Mita 	__be16 csum;
2382beb40ea4SAkinobu Mita 
238351d648afSAkinobu Mita 	if (scsi_debug_guard)
238451d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
238551d648afSAkinobu Mita 	else
2386beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
238751d648afSAkinobu Mita 
2388beb40ea4SAkinobu Mita 	return csum;
2389beb40ea4SAkinobu Mita }
2390beb40ea4SAkinobu Mita 
2391beb40ea4SAkinobu Mita static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
2392beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
2393beb40ea4SAkinobu Mita {
239451d648afSAkinobu Mita 	__be16 csum = dif_compute_csum(data, scsi_debug_sector_size);
2395beb40ea4SAkinobu Mita 
2396beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
2397beb40ea4SAkinobu Mita 		pr_err("%s: GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
2398beb40ea4SAkinobu Mita 			__func__,
2399beb40ea4SAkinobu Mita 			(unsigned long)sector,
2400beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
2401beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
2402beb40ea4SAkinobu Mita 		return 0x01;
2403beb40ea4SAkinobu Mita 	}
2404beb40ea4SAkinobu Mita 	if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
2405beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
2406beb40ea4SAkinobu Mita 		pr_err("%s: REF check failed on sector %lu\n",
2407beb40ea4SAkinobu Mita 			__func__, (unsigned long)sector);
2408beb40ea4SAkinobu Mita 		return 0x03;
2409beb40ea4SAkinobu Mita 	}
2410beb40ea4SAkinobu Mita 	if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
2411beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
2412beb40ea4SAkinobu Mita 		pr_err("%s: REF check failed on sector %lu\n",
2413beb40ea4SAkinobu Mita 			__func__, (unsigned long)sector);
2414beb40ea4SAkinobu Mita 		return 0x03;
2415beb40ea4SAkinobu Mita 	}
2416beb40ea4SAkinobu Mita 	return 0;
2417beb40ea4SAkinobu Mita }
2418beb40ea4SAkinobu Mita 
2419bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
242065f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
2421c6a44287SMartin K. Petersen {
2422be4e11beSAkinobu Mita 	size_t resid;
2423c6a44287SMartin K. Petersen 	void *paddr;
242414faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
2425be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
2426c6a44287SMartin K. Petersen 
2427e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
2428e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
2429c6a44287SMartin K. Petersen 
2430be4e11beSAkinobu Mita 	sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2431be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2432be4e11beSAkinobu Mita 			(read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2433be4e11beSAkinobu Mita 
2434be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
2435be4e11beSAkinobu Mita 		size_t len = min(miter.length, resid);
243614faa944SAkinobu Mita 		void *start = dif_store(sector);
2437be4e11beSAkinobu Mita 		size_t rest = 0;
243814faa944SAkinobu Mita 
243914faa944SAkinobu Mita 		if (dif_store_end < start + len)
244014faa944SAkinobu Mita 			rest = start + len - dif_store_end;
2441c6a44287SMartin K. Petersen 
2442be4e11beSAkinobu Mita 		paddr = miter.addr;
244314faa944SAkinobu Mita 
244465f72f2aSAkinobu Mita 		if (read)
244565f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
244665f72f2aSAkinobu Mita 		else
244765f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
244865f72f2aSAkinobu Mita 
244965f72f2aSAkinobu Mita 		if (rest) {
245065f72f2aSAkinobu Mita 			if (read)
245114faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
245265f72f2aSAkinobu Mita 			else
245365f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
245465f72f2aSAkinobu Mita 		}
2455c6a44287SMartin K. Petersen 
2456e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
2457c6a44287SMartin K. Petersen 		resid -= len;
2458c6a44287SMartin K. Petersen 	}
2459be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
2460bb8c063cSAkinobu Mita }
2461c6a44287SMartin K. Petersen 
2462bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2463bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
2464bb8c063cSAkinobu Mita {
2465bb8c063cSAkinobu Mita 	unsigned int i;
2466bb8c063cSAkinobu Mita 	struct sd_dif_tuple *sdt;
2467bb8c063cSAkinobu Mita 	sector_t sector;
2468bb8c063cSAkinobu Mita 
2469c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
2470bb8c063cSAkinobu Mita 		int ret;
2471bb8c063cSAkinobu Mita 
2472bb8c063cSAkinobu Mita 		sector = start_sec + i;
2473bb8c063cSAkinobu Mita 		sdt = dif_store(sector);
2474bb8c063cSAkinobu Mita 
247551d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
2476bb8c063cSAkinobu Mita 			continue;
2477bb8c063cSAkinobu Mita 
2478bb8c063cSAkinobu Mita 		ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2479bb8c063cSAkinobu Mita 		if (ret) {
2480bb8c063cSAkinobu Mita 			dif_errors++;
2481bb8c063cSAkinobu Mita 			return ret;
2482bb8c063cSAkinobu Mita 		}
2483bb8c063cSAkinobu Mita 	}
2484bb8c063cSAkinobu Mita 
248565f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, true);
2486c6a44287SMartin K. Petersen 	dix_reads++;
2487c6a44287SMartin K. Petersen 
2488c6a44287SMartin K. Petersen 	return 0;
2489c6a44287SMartin K. Petersen }
2490c6a44287SMartin K. Petersen 
2491c2248fc9SDouglas Gilbert static int
2492c2248fc9SDouglas Gilbert resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
249319789100SFUJITA Tomonori {
2494c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2495c2248fc9SDouglas Gilbert 	u64 lba;
2496c2248fc9SDouglas Gilbert 	u32 num;
2497c2248fc9SDouglas Gilbert 	u32 ei_lba;
249819789100SFUJITA Tomonori 	unsigned long iflags;
249919789100SFUJITA Tomonori 	int ret;
2500c2248fc9SDouglas Gilbert 	bool check_prot;
250119789100SFUJITA Tomonori 
2502c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2503c2248fc9SDouglas Gilbert 	case READ_16:
2504c2248fc9SDouglas Gilbert 		ei_lba = 0;
2505c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2506c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2507c2248fc9SDouglas Gilbert 		check_prot = true;
2508c2248fc9SDouglas Gilbert 		break;
2509c2248fc9SDouglas Gilbert 	case READ_10:
2510c2248fc9SDouglas Gilbert 		ei_lba = 0;
2511c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2512c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2513c2248fc9SDouglas Gilbert 		check_prot = true;
2514c2248fc9SDouglas Gilbert 		break;
2515c2248fc9SDouglas Gilbert 	case READ_6:
2516c2248fc9SDouglas Gilbert 		ei_lba = 0;
2517c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2518c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2519c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2520c2248fc9SDouglas Gilbert 		check_prot = true;
2521c2248fc9SDouglas Gilbert 		break;
2522c2248fc9SDouglas Gilbert 	case READ_12:
2523c2248fc9SDouglas Gilbert 		ei_lba = 0;
2524c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2525c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2526c2248fc9SDouglas Gilbert 		check_prot = true;
2527c2248fc9SDouglas Gilbert 		break;
2528c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
2529c2248fc9SDouglas Gilbert 		ei_lba = 0;
2530c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2531c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2532c2248fc9SDouglas Gilbert 		check_prot = false;
2533c2248fc9SDouglas Gilbert 		break;
2534c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
2535c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2536c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2537c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2538c2248fc9SDouglas Gilbert 		check_prot = false;
2539c2248fc9SDouglas Gilbert 		break;
2540c2248fc9SDouglas Gilbert 	}
2541c2248fc9SDouglas Gilbert 	if (check_prot) {
2542c2248fc9SDouglas Gilbert 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
2543c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2544c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2545c2248fc9SDouglas Gilbert 			return check_condition_result;
2546c2248fc9SDouglas Gilbert 		}
2547c2248fc9SDouglas Gilbert 		if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
2548c2248fc9SDouglas Gilbert 		     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
2549c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2550c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2551c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2552c2248fc9SDouglas Gilbert 	}
2553c2248fc9SDouglas Gilbert 	if (sdebug_any_injecting_opt) {
2554c2248fc9SDouglas Gilbert 		struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2555c2248fc9SDouglas Gilbert 
2556c2248fc9SDouglas Gilbert 		if (ep->inj_short)
2557c2248fc9SDouglas Gilbert 			num /= 2;
2558c2248fc9SDouglas Gilbert 	}
2559c2248fc9SDouglas Gilbert 
2560c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2561c2248fc9SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
2562c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2563c2248fc9SDouglas Gilbert 		return check_condition_result;
2564c2248fc9SDouglas Gilbert 	}
2565c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2566c2248fc9SDouglas Gilbert 	if (num > sdebug_store_sectors) {
2567c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2568c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2569c2248fc9SDouglas Gilbert 		return check_condition_result;
2570c2248fc9SDouglas Gilbert 	}
257119789100SFUJITA Tomonori 
25721da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
257332f7ef73SDouglas Gilbert 	    (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
2574c65b1445SDouglas Gilbert 	    ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
2575c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
2576c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
2577c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
2578c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2579c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
258032f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
258132f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
2582c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
2583c65b1445SDouglas Gilbert 		}
2584c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
25851da177e4SLinus Torvalds 		return check_condition_result;
25861da177e4SLinus Torvalds 	}
2587c6a44287SMartin K. Petersen 
25886c78cc06SAkinobu Mita 	read_lock_irqsave(&atomic_rw, iflags);
25896c78cc06SAkinobu Mita 
2590c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2591c2248fc9SDouglas Gilbert 	if (scsi_debug_dix && scsi_prot_sg_count(scp)) {
2592c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
2593c6a44287SMartin K. Petersen 
2594c6a44287SMartin K. Petersen 		if (prot_ret) {
25956c78cc06SAkinobu Mita 			read_unlock_irqrestore(&atomic_rw, iflags);
2596c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
2597c6a44287SMartin K. Petersen 			return illegal_condition_result;
2598c6a44287SMartin K. Petersen 		}
2599c6a44287SMartin K. Petersen 	}
2600c6a44287SMartin K. Petersen 
2601c2248fc9SDouglas Gilbert 	ret = do_device_access(scp, lba, num, false);
26021da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
2603a4517511SAkinobu Mita 	if (ret == -1)
2604a4517511SAkinobu Mita 		return DID_ERROR << 16;
2605a4517511SAkinobu Mita 
2606c2248fc9SDouglas Gilbert 	scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
2607a4517511SAkinobu Mita 
2608c2248fc9SDouglas Gilbert 	if (sdebug_any_injecting_opt) {
2609c2248fc9SDouglas Gilbert 		struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2610c2248fc9SDouglas Gilbert 
2611c2248fc9SDouglas Gilbert 		if (ep->inj_recovered) {
2612c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
2613c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
2614c2248fc9SDouglas Gilbert 			return check_condition_result;
2615c2248fc9SDouglas Gilbert 		} else if (ep->inj_transport) {
2616c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND,
2617c2248fc9SDouglas Gilbert 					TRANSPORT_PROBLEM, ACK_NAK_TO);
2618c2248fc9SDouglas Gilbert 			return check_condition_result;
2619c2248fc9SDouglas Gilbert 		} else if (ep->inj_dif) {
2620c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
2621c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2622c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2623c2248fc9SDouglas Gilbert 		} else if (ep->inj_dix) {
2624c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2625c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2626c2248fc9SDouglas Gilbert 		}
2627c2248fc9SDouglas Gilbert 	}
2628a4517511SAkinobu Mita 	return 0;
26291da177e4SLinus Torvalds }
26301da177e4SLinus Torvalds 
2631c6a44287SMartin K. Petersen void dump_sector(unsigned char *buf, int len)
2632c6a44287SMartin K. Petersen {
2633cbf67842SDouglas Gilbert 	int i, j, n;
2634c6a44287SMartin K. Petersen 
2635cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
2636c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
2637cbf67842SDouglas Gilbert 		char b[128];
2638c6a44287SMartin K. Petersen 
2639cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
2640c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
2641c6a44287SMartin K. Petersen 
2642cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
2643cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2644cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
2645cbf67842SDouglas Gilbert 			else
2646cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2647cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
2648cbf67842SDouglas Gilbert 		}
2649cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
2650c6a44287SMartin K. Petersen 	}
2651c6a44287SMartin K. Petersen }
2652c6a44287SMartin K. Petersen 
2653c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
2654395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
2655c6a44287SMartin K. Petersen {
2656be4e11beSAkinobu Mita 	int ret;
2657c6a44287SMartin K. Petersen 	struct sd_dif_tuple *sdt;
2658be4e11beSAkinobu Mita 	void *daddr;
265965f72f2aSAkinobu Mita 	sector_t sector = start_sec;
2660c6a44287SMartin K. Petersen 	int ppage_offset;
2661be4e11beSAkinobu Mita 	int dpage_offset;
2662be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
2663be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
2664c6a44287SMartin K. Petersen 
2665c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
2666c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2667c6a44287SMartin K. Petersen 
2668be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2669be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
2670be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2671be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2672be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2673c6a44287SMartin K. Petersen 
2674be4e11beSAkinobu Mita 	/* For each protection page */
2675be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
2676be4e11beSAkinobu Mita 		dpage_offset = 0;
2677be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
2678be4e11beSAkinobu Mita 			ret = 0x01;
2679be4e11beSAkinobu Mita 			goto out;
2680c6a44287SMartin K. Petersen 		}
2681c6a44287SMartin K. Petersen 
2682be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
2683be4e11beSAkinobu Mita 		     ppage_offset += sizeof(struct sd_dif_tuple)) {
2684be4e11beSAkinobu Mita 			/* If we're at the end of the current
2685be4e11beSAkinobu Mita 			 * data page advance to the next one
2686be4e11beSAkinobu Mita 			 */
2687be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
2688be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
2689be4e11beSAkinobu Mita 					ret = 0x01;
2690be4e11beSAkinobu Mita 					goto out;
2691be4e11beSAkinobu Mita 				}
2692be4e11beSAkinobu Mita 				dpage_offset = 0;
2693be4e11beSAkinobu Mita 			}
2694c6a44287SMartin K. Petersen 
2695be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
2696be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
2697be4e11beSAkinobu Mita 
2698be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
2699beb40ea4SAkinobu Mita 			if (ret) {
2700be4e11beSAkinobu Mita 				dump_sector(daddr, scsi_debug_sector_size);
2701395cef03SMartin K. Petersen 				goto out;
2702395cef03SMartin K. Petersen 			}
2703395cef03SMartin K. Petersen 
2704c6a44287SMartin K. Petersen 			sector++;
2705395cef03SMartin K. Petersen 			ei_lba++;
2706be4e11beSAkinobu Mita 			dpage_offset += scsi_debug_sector_size;
2707c6a44287SMartin K. Petersen 		}
2708be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
2709be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
2710c6a44287SMartin K. Petersen 	}
2711be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2712c6a44287SMartin K. Petersen 
271365f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
2714c6a44287SMartin K. Petersen 	dix_writes++;
2715c6a44287SMartin K. Petersen 
2716c6a44287SMartin K. Petersen 	return 0;
2717c6a44287SMartin K. Petersen 
2718c6a44287SMartin K. Petersen out:
2719c6a44287SMartin K. Petersen 	dif_errors++;
2720be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
2721be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2722c6a44287SMartin K. Petersen 	return ret;
2723c6a44287SMartin K. Petersen }
2724c6a44287SMartin K. Petersen 
2725b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
2726b90ebc3dSAkinobu Mita {
2727b90ebc3dSAkinobu Mita 	if (scsi_debug_unmap_alignment) {
2728b90ebc3dSAkinobu Mita 		lba += scsi_debug_unmap_granularity -
2729b90ebc3dSAkinobu Mita 			scsi_debug_unmap_alignment;
2730b90ebc3dSAkinobu Mita 	}
2731b90ebc3dSAkinobu Mita 	do_div(lba, scsi_debug_unmap_granularity);
2732b90ebc3dSAkinobu Mita 
2733b90ebc3dSAkinobu Mita 	return lba;
2734b90ebc3dSAkinobu Mita }
2735b90ebc3dSAkinobu Mita 
2736b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
2737b90ebc3dSAkinobu Mita {
2738a027b5b9SAkinobu Mita 	sector_t lba = index * scsi_debug_unmap_granularity;
2739a027b5b9SAkinobu Mita 
2740a027b5b9SAkinobu Mita 	if (scsi_debug_unmap_alignment) {
2741a027b5b9SAkinobu Mita 		lba -= scsi_debug_unmap_granularity -
2742b90ebc3dSAkinobu Mita 			scsi_debug_unmap_alignment;
2743b90ebc3dSAkinobu Mita 	}
2744b90ebc3dSAkinobu Mita 
2745a027b5b9SAkinobu Mita 	return lba;
2746a027b5b9SAkinobu Mita }
2747a027b5b9SAkinobu Mita 
274844d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
274944d92694SMartin K. Petersen {
2750b90ebc3dSAkinobu Mita 	sector_t end;
2751b90ebc3dSAkinobu Mita 	unsigned int mapped;
2752b90ebc3dSAkinobu Mita 	unsigned long index;
2753b90ebc3dSAkinobu Mita 	unsigned long next;
275444d92694SMartin K. Petersen 
2755b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
2756b90ebc3dSAkinobu Mita 	mapped = test_bit(index, map_storep);
275744d92694SMartin K. Petersen 
275844d92694SMartin K. Petersen 	if (mapped)
2759b90ebc3dSAkinobu Mita 		next = find_next_zero_bit(map_storep, map_size, index);
276044d92694SMartin K. Petersen 	else
2761b90ebc3dSAkinobu Mita 		next = find_next_bit(map_storep, map_size, index);
276244d92694SMartin K. Petersen 
2763b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
276444d92694SMartin K. Petersen 	*num = end - lba;
276544d92694SMartin K. Petersen 
276644d92694SMartin K. Petersen 	return mapped;
276744d92694SMartin K. Petersen }
276844d92694SMartin K. Petersen 
276944d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
277044d92694SMartin K. Petersen {
277144d92694SMartin K. Petersen 	sector_t end = lba + len;
277244d92694SMartin K. Petersen 
277344d92694SMartin K. Petersen 	while (lba < end) {
2774b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
277544d92694SMartin K. Petersen 
2776b90ebc3dSAkinobu Mita 		if (index < map_size)
2777b90ebc3dSAkinobu Mita 			set_bit(index, map_storep);
277844d92694SMartin K. Petersen 
2779b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
278044d92694SMartin K. Petersen 	}
278144d92694SMartin K. Petersen }
278244d92694SMartin K. Petersen 
278344d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
278444d92694SMartin K. Petersen {
278544d92694SMartin K. Petersen 	sector_t end = lba + len;
278644d92694SMartin K. Petersen 
278744d92694SMartin K. Petersen 	while (lba < end) {
2788b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
278944d92694SMartin K. Petersen 
2790b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
2791b90ebc3dSAkinobu Mita 		    lba + scsi_debug_unmap_granularity <= end &&
2792b90ebc3dSAkinobu Mita 		    index < map_size) {
2793b90ebc3dSAkinobu Mita 			clear_bit(index, map_storep);
2794b90ebc3dSAkinobu Mita 			if (scsi_debug_lbprz) {
2795be1dd78dSEric Sandeen 				memset(fake_storep +
2796cc34a8e6SAkinobu Mita 				       lba * scsi_debug_sector_size, 0,
2797cc34a8e6SAkinobu Mita 				       scsi_debug_sector_size *
2798cc34a8e6SAkinobu Mita 				       scsi_debug_unmap_granularity);
2799be1dd78dSEric Sandeen 			}
2800e9926b43SAkinobu Mita 			if (dif_storep) {
2801e9926b43SAkinobu Mita 				memset(dif_storep + lba, 0xff,
2802e9926b43SAkinobu Mita 				       sizeof(*dif_storep) *
2803e9926b43SAkinobu Mita 				       scsi_debug_unmap_granularity);
2804e9926b43SAkinobu Mita 			}
2805b90ebc3dSAkinobu Mita 		}
2806b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
280744d92694SMartin K. Petersen 	}
280844d92694SMartin K. Petersen }
280944d92694SMartin K. Petersen 
2810c2248fc9SDouglas Gilbert static int
2811c2248fc9SDouglas Gilbert resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
28121da177e4SLinus Torvalds {
2813c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2814c2248fc9SDouglas Gilbert 	u64 lba;
2815c2248fc9SDouglas Gilbert 	u32 num;
2816c2248fc9SDouglas Gilbert 	u32 ei_lba;
28171da177e4SLinus Torvalds 	unsigned long iflags;
281819789100SFUJITA Tomonori 	int ret;
2819c2248fc9SDouglas Gilbert 	bool check_prot;
28201da177e4SLinus Torvalds 
2821c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2822c2248fc9SDouglas Gilbert 	case WRITE_16:
2823c2248fc9SDouglas Gilbert 		ei_lba = 0;
2824c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2825c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2826c2248fc9SDouglas Gilbert 		check_prot = true;
2827c2248fc9SDouglas Gilbert 		break;
2828c2248fc9SDouglas Gilbert 	case WRITE_10:
2829c2248fc9SDouglas Gilbert 		ei_lba = 0;
2830c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2831c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2832c2248fc9SDouglas Gilbert 		check_prot = true;
2833c2248fc9SDouglas Gilbert 		break;
2834c2248fc9SDouglas Gilbert 	case WRITE_6:
2835c2248fc9SDouglas Gilbert 		ei_lba = 0;
2836c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2837c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2838c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2839c2248fc9SDouglas Gilbert 		check_prot = true;
2840c2248fc9SDouglas Gilbert 		break;
2841c2248fc9SDouglas Gilbert 	case WRITE_12:
2842c2248fc9SDouglas Gilbert 		ei_lba = 0;
2843c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2844c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2845c2248fc9SDouglas Gilbert 		check_prot = true;
2846c2248fc9SDouglas Gilbert 		break;
2847c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
2848c2248fc9SDouglas Gilbert 		ei_lba = 0;
2849c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2850c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2851c2248fc9SDouglas Gilbert 		check_prot = false;
2852c2248fc9SDouglas Gilbert 		break;
2853c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
2854c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2855c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2856c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2857c2248fc9SDouglas Gilbert 		check_prot = false;
2858c2248fc9SDouglas Gilbert 		break;
2859c2248fc9SDouglas Gilbert 	}
2860c2248fc9SDouglas Gilbert 	if (check_prot) {
2861c2248fc9SDouglas Gilbert 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
2862c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2863c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2864c2248fc9SDouglas Gilbert 			return check_condition_result;
2865c2248fc9SDouglas Gilbert 		}
2866c2248fc9SDouglas Gilbert 		if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
2867c2248fc9SDouglas Gilbert 		     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
2868c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2869c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2870c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2871c2248fc9SDouglas Gilbert 	}
2872c2248fc9SDouglas Gilbert 
2873c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2874c2248fc9SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
2875c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2876c2248fc9SDouglas Gilbert 		return check_condition_result;
2877c2248fc9SDouglas Gilbert 	}
2878c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2879c2248fc9SDouglas Gilbert 	if (num > sdebug_store_sectors) {
2880c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2881c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2882c2248fc9SDouglas Gilbert 		return check_condition_result;
2883c2248fc9SDouglas Gilbert 	}
28841da177e4SLinus Torvalds 
28856c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
28866c78cc06SAkinobu Mita 
2887c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2888c2248fc9SDouglas Gilbert 	if (scsi_debug_dix && scsi_prot_sg_count(scp)) {
2889c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
2890c6a44287SMartin K. Petersen 
2891c6a44287SMartin K. Petersen 		if (prot_ret) {
28926c78cc06SAkinobu Mita 			write_unlock_irqrestore(&atomic_rw, iflags);
2893c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
2894c6a44287SMartin K. Petersen 			return illegal_condition_result;
2895c6a44287SMartin K. Petersen 		}
2896c6a44287SMartin K. Petersen 	}
2897c6a44287SMartin K. Petersen 
2898c2248fc9SDouglas Gilbert 	ret = do_device_access(scp, lba, num, true);
28999ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
290044d92694SMartin K. Petersen 		map_region(lba, num);
29011da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
290219789100SFUJITA Tomonori 	if (-1 == ret)
29031da177e4SLinus Torvalds 		return (DID_ERROR << 16);
2904597136abSMartin K. Petersen 	else if ((ret < (num * scsi_debug_sector_size)) &&
29051da177e4SLinus Torvalds 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
2906c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2907cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
2908cbf67842SDouglas Gilbert 			    my_name, num * scsi_debug_sector_size, ret);
290944d92694SMartin K. Petersen 
2910c2248fc9SDouglas Gilbert 	if (sdebug_any_injecting_opt) {
2911c2248fc9SDouglas Gilbert 		struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2912c2248fc9SDouglas Gilbert 
2913c2248fc9SDouglas Gilbert 		if (ep->inj_recovered) {
2914c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
2915c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
2916c2248fc9SDouglas Gilbert 			return check_condition_result;
2917c2248fc9SDouglas Gilbert 		} else if (ep->inj_dif) {
2918c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
2919c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2920c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2921c2248fc9SDouglas Gilbert 		} else if (ep->inj_dix) {
2922c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2923c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2924c2248fc9SDouglas Gilbert 		}
2925c2248fc9SDouglas Gilbert 	}
29261da177e4SLinus Torvalds 	return 0;
29271da177e4SLinus Torvalds }
29281da177e4SLinus Torvalds 
2929c2248fc9SDouglas Gilbert static int
2930c2248fc9SDouglas Gilbert resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, u32 ei_lba,
2931c2248fc9SDouglas Gilbert 		bool unmap, bool ndob)
293244d92694SMartin K. Petersen {
293344d92694SMartin K. Petersen 	unsigned long iflags;
293444d92694SMartin K. Petersen 	unsigned long long i;
293544d92694SMartin K. Petersen 	int ret;
293644d92694SMartin K. Petersen 
2937c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num);
293844d92694SMartin K. Petersen 	if (ret)
293944d92694SMartin K. Petersen 		return ret;
294044d92694SMartin K. Petersen 
294144d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
294244d92694SMartin K. Petersen 
29439ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
294444d92694SMartin K. Petersen 		unmap_region(lba, num);
294544d92694SMartin K. Petersen 		goto out;
294644d92694SMartin K. Petersen 	}
294744d92694SMartin K. Petersen 
2948c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
2949c2248fc9SDouglas Gilbert 	if (ndob) {
2950c2248fc9SDouglas Gilbert 		memset(fake_storep + (lba * scsi_debug_sector_size), 0,
2951c2248fc9SDouglas Gilbert 		       scsi_debug_sector_size);
2952c2248fc9SDouglas Gilbert 		ret = 0;
2953c2248fc9SDouglas Gilbert 	} else
2954c2248fc9SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fake_storep +
2955c2248fc9SDouglas Gilbert 					       (lba * scsi_debug_sector_size),
295644d92694SMartin K. Petersen 					  scsi_debug_sector_size);
295744d92694SMartin K. Petersen 
295844d92694SMartin K. Petersen 	if (-1 == ret) {
295944d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
296044d92694SMartin K. Petersen 		return (DID_ERROR << 16);
296144d92694SMartin K. Petersen 	} else if ((ret < (num * scsi_debug_sector_size)) &&
296244d92694SMartin K. Petersen 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
2963c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2964cbf67842SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
2965cbf67842SDouglas Gilbert 			    my_name, "write same",
2966cbf67842SDouglas Gilbert 			    num * scsi_debug_sector_size, ret);
296744d92694SMartin K. Petersen 
296844d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
296944d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
297044d92694SMartin K. Petersen 		memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size),
297144d92694SMartin K. Petersen 		       fake_storep + (lba * scsi_debug_sector_size),
297244d92694SMartin K. Petersen 		       scsi_debug_sector_size);
297344d92694SMartin K. Petersen 
29749ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
297544d92694SMartin K. Petersen 		map_region(lba, num);
297644d92694SMartin K. Petersen out:
297744d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
297844d92694SMartin K. Petersen 
297944d92694SMartin K. Petersen 	return 0;
298044d92694SMartin K. Petersen }
298144d92694SMartin K. Petersen 
2982c2248fc9SDouglas Gilbert static int
2983c2248fc9SDouglas Gilbert resp_write_same_10(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
2984c2248fc9SDouglas Gilbert {
2985c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2986c2248fc9SDouglas Gilbert 	u32 lba;
2987c2248fc9SDouglas Gilbert 	u16 num;
2988c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
2989c2248fc9SDouglas Gilbert 	bool unmap = false;
2990c2248fc9SDouglas Gilbert 
2991c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
2992c2248fc9SDouglas Gilbert 		if (scsi_debug_lbpws10 == 0) {
2993c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
2994c2248fc9SDouglas Gilbert 			return check_condition_result;
2995c2248fc9SDouglas Gilbert 		} else
2996c2248fc9SDouglas Gilbert 			unmap = true;
2997c2248fc9SDouglas Gilbert 	}
2998c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
2999c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3000c2248fc9SDouglas Gilbert 	if (num > scsi_debug_write_same_length) {
3001c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3002c2248fc9SDouglas Gilbert 		return check_condition_result;
3003c2248fc9SDouglas Gilbert 	}
3004c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3005c2248fc9SDouglas Gilbert }
3006c2248fc9SDouglas Gilbert 
3007c2248fc9SDouglas Gilbert static int
3008c2248fc9SDouglas Gilbert resp_write_same_16(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
3009c2248fc9SDouglas Gilbert {
3010c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3011c2248fc9SDouglas Gilbert 	u64 lba;
3012c2248fc9SDouglas Gilbert 	u32 num;
3013c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
3014c2248fc9SDouglas Gilbert 	bool unmap = false;
3015c2248fc9SDouglas Gilbert 	bool ndob = false;
3016c2248fc9SDouglas Gilbert 
3017c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
3018c2248fc9SDouglas Gilbert 		if (scsi_debug_lbpws == 0) {
3019c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3020c2248fc9SDouglas Gilbert 			return check_condition_result;
3021c2248fc9SDouglas Gilbert 		} else
3022c2248fc9SDouglas Gilbert 			unmap = true;
3023c2248fc9SDouglas Gilbert 	}
3024c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
3025c2248fc9SDouglas Gilbert 		ndob = true;
3026c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3027c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
3028c2248fc9SDouglas Gilbert 	if (num > scsi_debug_write_same_length) {
3029c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3030c2248fc9SDouglas Gilbert 		return check_condition_result;
3031c2248fc9SDouglas Gilbert 	}
3032c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3033c2248fc9SDouglas Gilbert }
3034c2248fc9SDouglas Gilbert 
303538d5c833SDouglas Gilbert static int
303638d5c833SDouglas Gilbert resp_comp_write(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
303738d5c833SDouglas Gilbert {
303838d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
303938d5c833SDouglas Gilbert 	u8 *arr;
304038d5c833SDouglas Gilbert 	u8 *fake_storep_hold;
304138d5c833SDouglas Gilbert 	u64 lba;
304238d5c833SDouglas Gilbert 	u32 dnum;
304338d5c833SDouglas Gilbert 	u32 lb_size = scsi_debug_sector_size;
304438d5c833SDouglas Gilbert 	u8 num;
304538d5c833SDouglas Gilbert 	unsigned long iflags;
304638d5c833SDouglas Gilbert 	int ret;
3047d467d31fSDouglas Gilbert 	int retval = 0;
304838d5c833SDouglas Gilbert 
3049d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
305038d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
305138d5c833SDouglas Gilbert 	if (0 == num)
305238d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
305338d5c833SDouglas Gilbert 	if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
305438d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
305538d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
305638d5c833SDouglas Gilbert 		return check_condition_result;
305738d5c833SDouglas Gilbert 	}
305838d5c833SDouglas Gilbert 	if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
305938d5c833SDouglas Gilbert 	     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
306038d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
306138d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
306238d5c833SDouglas Gilbert 			    "to DIF device\n");
306338d5c833SDouglas Gilbert 
306438d5c833SDouglas Gilbert 	/* inline check_device_access_params() */
306538d5c833SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
306638d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
306738d5c833SDouglas Gilbert 		return check_condition_result;
306838d5c833SDouglas Gilbert 	}
306938d5c833SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
307038d5c833SDouglas Gilbert 	if (num > sdebug_store_sectors) {
307138d5c833SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
307238d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
307338d5c833SDouglas Gilbert 		return check_condition_result;
307438d5c833SDouglas Gilbert 	}
3075d467d31fSDouglas Gilbert 	dnum = 2 * num;
3076d467d31fSDouglas Gilbert 	arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3077d467d31fSDouglas Gilbert 	if (NULL == arr) {
3078d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3079d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3080d467d31fSDouglas Gilbert 		return check_condition_result;
3081d467d31fSDouglas Gilbert 	}
308238d5c833SDouglas Gilbert 
308338d5c833SDouglas Gilbert 	write_lock_irqsave(&atomic_rw, iflags);
308438d5c833SDouglas Gilbert 
308538d5c833SDouglas Gilbert 	/* trick do_device_access() to fetch both compare and write buffers
308638d5c833SDouglas Gilbert 	 * from data-in into arr. Safe (atomic) since write_lock held. */
308738d5c833SDouglas Gilbert 	fake_storep_hold = fake_storep;
308838d5c833SDouglas Gilbert 	fake_storep = arr;
308938d5c833SDouglas Gilbert 	ret = do_device_access(scp, 0, dnum, true);
309038d5c833SDouglas Gilbert 	fake_storep = fake_storep_hold;
309138d5c833SDouglas Gilbert 	if (ret == -1) {
3092d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3093d467d31fSDouglas Gilbert 		goto cleanup;
309438d5c833SDouglas Gilbert 	} else if ((ret < (dnum * lb_size)) &&
309538d5c833SDouglas Gilbert 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
309638d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
309738d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
309838d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
309938d5c833SDouglas Gilbert 	if (!comp_write_worker(lba, num, arr)) {
310038d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3101d467d31fSDouglas Gilbert 		retval = check_condition_result;
3102d467d31fSDouglas Gilbert 		goto cleanup;
310338d5c833SDouglas Gilbert 	}
310438d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
310538d5c833SDouglas Gilbert 		map_region(lba, num);
3106d467d31fSDouglas Gilbert cleanup:
310738d5c833SDouglas Gilbert 	write_unlock_irqrestore(&atomic_rw, iflags);
3108d467d31fSDouglas Gilbert 	kfree(arr);
3109d467d31fSDouglas Gilbert 	return retval;
311038d5c833SDouglas Gilbert }
311138d5c833SDouglas Gilbert 
311244d92694SMartin K. Petersen struct unmap_block_desc {
311344d92694SMartin K. Petersen 	__be64	lba;
311444d92694SMartin K. Petersen 	__be32	blocks;
311544d92694SMartin K. Petersen 	__be32	__reserved;
311644d92694SMartin K. Petersen };
311744d92694SMartin K. Petersen 
3118c2248fc9SDouglas Gilbert static int
3119c2248fc9SDouglas Gilbert resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
312044d92694SMartin K. Petersen {
312144d92694SMartin K. Petersen 	unsigned char *buf;
312244d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
312344d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
312444d92694SMartin K. Petersen 	int ret;
31256c78cc06SAkinobu Mita 	unsigned long iflags;
312644d92694SMartin K. Petersen 
312744d92694SMartin K. Petersen 
3128c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3129c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3130c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3131c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
313244d92694SMartin K. Petersen 
313344d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3134c2248fc9SDouglas Gilbert 	if (descriptors > scsi_debug_unmap_max_desc) {
3135c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
313644d92694SMartin K. Petersen 		return check_condition_result;
3137c2248fc9SDouglas Gilbert 	}
313844d92694SMartin K. Petersen 
3139c2248fc9SDouglas Gilbert 	buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
3140c2248fc9SDouglas Gilbert 	if (!buf) {
3141c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3142c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3143c2248fc9SDouglas Gilbert 		return check_condition_result;
3144c2248fc9SDouglas Gilbert 	}
3145c2248fc9SDouglas Gilbert 
3146c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
314744d92694SMartin K. Petersen 
314844d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
314944d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
315044d92694SMartin K. Petersen 
315144d92694SMartin K. Petersen 	desc = (void *)&buf[8];
315244d92694SMartin K. Petersen 
31536c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
31546c78cc06SAkinobu Mita 
315544d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
315644d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
315744d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
315844d92694SMartin K. Petersen 
3159c2248fc9SDouglas Gilbert 		ret = check_device_access_params(scp, lba, num);
316044d92694SMartin K. Petersen 		if (ret)
316144d92694SMartin K. Petersen 			goto out;
316244d92694SMartin K. Petersen 
316344d92694SMartin K. Petersen 		unmap_region(lba, num);
316444d92694SMartin K. Petersen 	}
316544d92694SMartin K. Petersen 
316644d92694SMartin K. Petersen 	ret = 0;
316744d92694SMartin K. Petersen 
316844d92694SMartin K. Petersen out:
31696c78cc06SAkinobu Mita 	write_unlock_irqrestore(&atomic_rw, iflags);
317044d92694SMartin K. Petersen 	kfree(buf);
317144d92694SMartin K. Petersen 
317244d92694SMartin K. Petersen 	return ret;
317344d92694SMartin K. Petersen }
317444d92694SMartin K. Petersen 
317544d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
317644d92694SMartin K. Petersen 
3177c2248fc9SDouglas Gilbert static int
3178c2248fc9SDouglas Gilbert resp_get_lba_status(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
317944d92694SMartin K. Petersen {
3180c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3181c2248fc9SDouglas Gilbert 	u64 lba;
3182c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
3183c2248fc9SDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
318444d92694SMartin K. Petersen 	int ret;
318544d92694SMartin K. Petersen 
3186c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3187c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
318844d92694SMartin K. Petersen 
318944d92694SMartin K. Petersen 	if (alloc_len < 24)
319044d92694SMartin K. Petersen 		return 0;
319144d92694SMartin K. Petersen 
3192c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, 1);
319344d92694SMartin K. Petersen 	if (ret)
319444d92694SMartin K. Petersen 		return ret;
319544d92694SMartin K. Petersen 
3196c2248fc9SDouglas Gilbert 	if (scsi_debug_lbp())
319744d92694SMartin K. Petersen 		mapped = map_state(lba, &num);
3198c2248fc9SDouglas Gilbert 	else {
3199c2248fc9SDouglas Gilbert 		mapped = 1;
3200c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
3201c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
3202c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
3203c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
3204c2248fc9SDouglas Gilbert 		else
3205c2248fc9SDouglas Gilbert 			num = 0xffffffff;
3206c2248fc9SDouglas Gilbert 	}
320744d92694SMartin K. Petersen 
320844d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
3209c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
3210c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
3211c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
3212c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
321344d92694SMartin K. Petersen 
3214c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
321544d92694SMartin K. Petersen }
321644d92694SMartin K. Petersen 
3217c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256
32181da177e4SLinus Torvalds 
32191da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp,
32201da177e4SLinus Torvalds 			    struct sdebug_dev_info * devip)
32211da177e4SLinus Torvalds {
32221da177e4SLinus Torvalds 	unsigned int alloc_len;
322322017ed2SDouglas Gilbert 	int lun_cnt, i, upper, num, n, want_wlun, shortish;
322422017ed2SDouglas Gilbert 	u64 lun;
322501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
32261da177e4SLinus Torvalds 	int select_report = (int)cmd[2];
32271da177e4SLinus Torvalds 	struct scsi_lun *one_lun;
32281da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_RLUN_ARR_SZ];
3229c65b1445SDouglas Gilbert 	unsigned char * max_addr;
32301da177e4SLinus Torvalds 
32311da177e4SLinus Torvalds 	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
323222017ed2SDouglas Gilbert 	shortish = (alloc_len < 4);
323322017ed2SDouglas Gilbert 	if (shortish || (select_report > 2)) {
323422017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, shortish ? 6 : 2, -1);
32351da177e4SLinus Torvalds 		return check_condition_result;
32361da177e4SLinus Torvalds 	}
32371da177e4SLinus Torvalds 	/* can produce response with up to 16k luns (lun 0 to lun 16383) */
32381da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
32391da177e4SLinus Torvalds 	lun_cnt = scsi_debug_max_luns;
3240c65b1445SDouglas Gilbert 	if (1 == select_report)
3241c65b1445SDouglas Gilbert 		lun_cnt = 0;
3242c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
3243c65b1445SDouglas Gilbert 		--lun_cnt;
324422017ed2SDouglas Gilbert 	want_wlun = (select_report > 0) ? 1 : 0;
324522017ed2SDouglas Gilbert 	num = lun_cnt + want_wlun;
3246c65b1445SDouglas Gilbert 	arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
3247c65b1445SDouglas Gilbert 	arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
3248c65b1445SDouglas Gilbert 	n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
3249c65b1445SDouglas Gilbert 			    sizeof(struct scsi_lun)), num);
3250c65b1445SDouglas Gilbert 	if (n < num) {
325122017ed2SDouglas Gilbert 		want_wlun = 0;
3252c65b1445SDouglas Gilbert 		lun_cnt = n;
3253c65b1445SDouglas Gilbert 	}
32541da177e4SLinus Torvalds 	one_lun = (struct scsi_lun *) &arr[8];
3255c65b1445SDouglas Gilbert 	max_addr = arr + SDEBUG_RLUN_ARR_SZ;
3256c65b1445SDouglas Gilbert 	for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
3257c65b1445SDouglas Gilbert              ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
3258c65b1445SDouglas Gilbert 	     i++, lun++) {
3259c65b1445SDouglas Gilbert 		upper = (lun >> 8) & 0x3f;
32601da177e4SLinus Torvalds 		if (upper)
32611da177e4SLinus Torvalds 			one_lun[i].scsi_lun[0] =
32621da177e4SLinus Torvalds 			    (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
3263c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = lun & 0xff;
32641da177e4SLinus Torvalds 	}
326522017ed2SDouglas Gilbert 	if (want_wlun) {
3266c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
3267c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
3268c65b1445SDouglas Gilbert 		i++;
3269c65b1445SDouglas Gilbert 	}
3270c65b1445SDouglas Gilbert 	alloc_len = (unsigned char *)(one_lun + i) - arr;
32711da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr,
32721da177e4SLinus Torvalds 				    min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
32731da177e4SLinus Torvalds }
32741da177e4SLinus Torvalds 
3275c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3276c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
3277c639d14eSFUJITA Tomonori {
3278be4e11beSAkinobu Mita 	int j;
3279c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
3280c639d14eSFUJITA Tomonori 	unsigned int offset;
3281c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
3282be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3283c639d14eSFUJITA Tomonori 
3284c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
3285c639d14eSFUJITA Tomonori 	buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
3286c5af0db9SAkinobu Mita 	if (!buf) {
328722017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
328822017ed2SDouglas Gilbert 				INSUFF_RES_ASCQ);
3289c5af0db9SAkinobu Mita 		return check_condition_result;
3290c5af0db9SAkinobu Mita 	}
3291c639d14eSFUJITA Tomonori 
329221a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
3293c639d14eSFUJITA Tomonori 
3294c639d14eSFUJITA Tomonori 	offset = 0;
3295be4e11beSAkinobu Mita 	sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3296be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_TO_SG);
3297c639d14eSFUJITA Tomonori 
3298be4e11beSAkinobu Mita 	while (sg_miter_next(&miter)) {
3299be4e11beSAkinobu Mita 		kaddr = miter.addr;
3300be4e11beSAkinobu Mita 		for (j = 0; j < miter.length; j++)
3301be4e11beSAkinobu Mita 			*(kaddr + j) ^= *(buf + offset + j);
3302c639d14eSFUJITA Tomonori 
3303be4e11beSAkinobu Mita 		offset += miter.length;
3304c639d14eSFUJITA Tomonori 	}
3305be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3306c639d14eSFUJITA Tomonori 	kfree(buf);
3307c639d14eSFUJITA Tomonori 
3308be4e11beSAkinobu Mita 	return 0;
3309c639d14eSFUJITA Tomonori }
3310c639d14eSFUJITA Tomonori 
3311c2248fc9SDouglas Gilbert static int
3312c2248fc9SDouglas Gilbert resp_xdwriteread_10(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
3313c2248fc9SDouglas Gilbert {
3314c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3315c2248fc9SDouglas Gilbert 	u64 lba;
3316c2248fc9SDouglas Gilbert 	u32 num;
3317c2248fc9SDouglas Gilbert 	int errsts;
3318c2248fc9SDouglas Gilbert 
3319c2248fc9SDouglas Gilbert 	if (!scsi_bidi_cmnd(scp)) {
3320c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3321c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3322c2248fc9SDouglas Gilbert 		return check_condition_result;
3323c2248fc9SDouglas Gilbert 	}
3324c2248fc9SDouglas Gilbert 	errsts = resp_read_dt0(scp, devip);
3325c2248fc9SDouglas Gilbert 	if (errsts)
3326c2248fc9SDouglas Gilbert 		return errsts;
3327c2248fc9SDouglas Gilbert 	if (!(cmd[1] & 0x4)) {		/* DISABLE_WRITE is not set */
3328c2248fc9SDouglas Gilbert 		errsts = resp_write_dt0(scp, devip);
3329c2248fc9SDouglas Gilbert 		if (errsts)
3330c2248fc9SDouglas Gilbert 			return errsts;
3331c2248fc9SDouglas Gilbert 	}
3332c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3333c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3334c2248fc9SDouglas Gilbert 	return resp_xdwriteread(scp, lba, num, devip);
3335c2248fc9SDouglas Gilbert }
3336c2248fc9SDouglas Gilbert 
3337cbf67842SDouglas Gilbert /* When timer or tasklet goes off this function is called. */
3338cbf67842SDouglas Gilbert static void sdebug_q_cmd_complete(unsigned long indx)
33391da177e4SLinus Torvalds {
3340cbf67842SDouglas Gilbert 	int qa_indx;
3341cbf67842SDouglas Gilbert 	int retiring = 0;
33421da177e4SLinus Torvalds 	unsigned long iflags;
3343cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3344cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
3345cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
33461da177e4SLinus Torvalds 
3347cbf67842SDouglas Gilbert 	atomic_inc(&sdebug_completions);
3348cbf67842SDouglas Gilbert 	qa_indx = indx;
3349cbf67842SDouglas Gilbert 	if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
3350cbf67842SDouglas Gilbert 		pr_err("%s: wild qa_indx=%d\n", __func__, qa_indx);
33511da177e4SLinus Torvalds 		return;
33521da177e4SLinus Torvalds 	}
33531da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
3354cbf67842SDouglas Gilbert 	sqcp = &queued_arr[qa_indx];
3355cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
3356cbf67842SDouglas Gilbert 	if (NULL == scp) {
33571da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
3358cbf67842SDouglas Gilbert 		pr_err("%s: scp is NULL\n", __func__);
33591da177e4SLinus Torvalds 		return;
33601da177e4SLinus Torvalds 	}
3361cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
3362cbf67842SDouglas Gilbert 	if (devip)
3363cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
3364cbf67842SDouglas Gilbert 	else
3365cbf67842SDouglas Gilbert 		pr_err("%s: devip=NULL\n", __func__);
3366cbf67842SDouglas Gilbert 	if (atomic_read(&retired_max_queue) > 0)
3367cbf67842SDouglas Gilbert 		retiring = 1;
3368cbf67842SDouglas Gilbert 
3369cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
3370cbf67842SDouglas Gilbert 	if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
33711da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
3372cbf67842SDouglas Gilbert 		pr_err("%s: Unexpected completion\n", __func__);
3373cbf67842SDouglas Gilbert 		return;
33741da177e4SLinus Torvalds 	}
33751da177e4SLinus Torvalds 
3376cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
3377cbf67842SDouglas Gilbert 		int k, retval;
3378cbf67842SDouglas Gilbert 
3379cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
3380cbf67842SDouglas Gilbert 		if (qa_indx >= retval) {
3381cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
3382cbf67842SDouglas Gilbert 			pr_err("%s: index %d too large\n", __func__, retval);
3383cbf67842SDouglas Gilbert 			return;
3384cbf67842SDouglas Gilbert 		}
3385cbf67842SDouglas Gilbert 		k = find_last_bit(queued_in_use_bm, retval);
3386cbf67842SDouglas Gilbert 		if ((k < scsi_debug_max_queue) || (k == retval))
3387cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3388cbf67842SDouglas Gilbert 		else
3389cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
3390cbf67842SDouglas Gilbert 	}
3391cbf67842SDouglas Gilbert 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
3392cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
3393cbf67842SDouglas Gilbert }
3394cbf67842SDouglas Gilbert 
3395cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
3396cbf67842SDouglas Gilbert static enum hrtimer_restart
3397cbf67842SDouglas Gilbert sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
3398cbf67842SDouglas Gilbert {
3399cbf67842SDouglas Gilbert 	int qa_indx;
3400cbf67842SDouglas Gilbert 	int retiring = 0;
3401cbf67842SDouglas Gilbert 	unsigned long iflags;
3402cbf67842SDouglas Gilbert 	struct sdebug_hrtimer *sd_hrtp = (struct sdebug_hrtimer *)timer;
3403cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3404cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
3405cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3406cbf67842SDouglas Gilbert 
3407cbf67842SDouglas Gilbert 	atomic_inc(&sdebug_completions);
3408cbf67842SDouglas Gilbert 	qa_indx = sd_hrtp->qa_indx;
3409cbf67842SDouglas Gilbert 	if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
3410cbf67842SDouglas Gilbert 		pr_err("%s: wild qa_indx=%d\n", __func__, qa_indx);
3411cbf67842SDouglas Gilbert 		goto the_end;
3412cbf67842SDouglas Gilbert 	}
3413cbf67842SDouglas Gilbert 	spin_lock_irqsave(&queued_arr_lock, iflags);
3414cbf67842SDouglas Gilbert 	sqcp = &queued_arr[qa_indx];
3415cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
3416cbf67842SDouglas Gilbert 	if (NULL == scp) {
3417cbf67842SDouglas Gilbert 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
3418cbf67842SDouglas Gilbert 		pr_err("%s: scp is NULL\n", __func__);
3419cbf67842SDouglas Gilbert 		goto the_end;
3420cbf67842SDouglas Gilbert 	}
3421cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
3422cbf67842SDouglas Gilbert 	if (devip)
3423cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
3424cbf67842SDouglas Gilbert 	else
3425cbf67842SDouglas Gilbert 		pr_err("%s: devip=NULL\n", __func__);
3426cbf67842SDouglas Gilbert 	if (atomic_read(&retired_max_queue) > 0)
3427cbf67842SDouglas Gilbert 		retiring = 1;
3428cbf67842SDouglas Gilbert 
3429cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
3430cbf67842SDouglas Gilbert 	if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
3431cbf67842SDouglas Gilbert 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
3432cbf67842SDouglas Gilbert 		pr_err("%s: Unexpected completion\n", __func__);
3433cbf67842SDouglas Gilbert 		goto the_end;
3434cbf67842SDouglas Gilbert 	}
3435cbf67842SDouglas Gilbert 
3436cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
3437cbf67842SDouglas Gilbert 		int k, retval;
3438cbf67842SDouglas Gilbert 
3439cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
3440cbf67842SDouglas Gilbert 		if (qa_indx >= retval) {
3441cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
3442cbf67842SDouglas Gilbert 			pr_err("%s: index %d too large\n", __func__, retval);
3443cbf67842SDouglas Gilbert 			goto the_end;
3444cbf67842SDouglas Gilbert 		}
3445cbf67842SDouglas Gilbert 		k = find_last_bit(queued_in_use_bm, retval);
3446cbf67842SDouglas Gilbert 		if ((k < scsi_debug_max_queue) || (k == retval))
3447cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3448cbf67842SDouglas Gilbert 		else
3449cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
3450cbf67842SDouglas Gilbert 	}
3451cbf67842SDouglas Gilbert 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
3452cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
3453cbf67842SDouglas Gilbert the_end:
3454cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
3455cbf67842SDouglas Gilbert }
34561da177e4SLinus Torvalds 
34578dea0d02SFUJITA Tomonori static struct sdebug_dev_info *
34588dea0d02SFUJITA Tomonori sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
34595cb2fc06SFUJITA Tomonori {
34605cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
34615cb2fc06SFUJITA Tomonori 
34625cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
34635cb2fc06SFUJITA Tomonori 	if (devip) {
34645cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
34655cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
34665cb2fc06SFUJITA Tomonori 	}
34675cb2fc06SFUJITA Tomonori 	return devip;
34685cb2fc06SFUJITA Tomonori }
34695cb2fc06SFUJITA Tomonori 
34701da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
34711da177e4SLinus Torvalds {
34721da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
34731da177e4SLinus Torvalds 	struct sdebug_dev_info * open_devip = NULL;
34741da177e4SLinus Torvalds 	struct sdebug_dev_info * devip =
34751da177e4SLinus Torvalds 			(struct sdebug_dev_info *)sdev->hostdata;
34761da177e4SLinus Torvalds 
34771da177e4SLinus Torvalds 	if (devip)
34781da177e4SLinus Torvalds 		return devip;
3479d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
34801da177e4SLinus Torvalds 	if (!sdbg_host) {
3481cbf67842SDouglas Gilbert 		pr_err("%s: Host info NULL\n", __func__);
34821da177e4SLinus Torvalds 		return NULL;
34831da177e4SLinus Torvalds         }
34841da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
34851da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
34861da177e4SLinus Torvalds                     (devip->target == sdev->id) &&
34871da177e4SLinus Torvalds                     (devip->lun == sdev->lun))
34881da177e4SLinus Torvalds                         return devip;
34891da177e4SLinus Torvalds 		else {
34901da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
34911da177e4SLinus Torvalds 				open_devip = devip;
34921da177e4SLinus Torvalds 		}
34931da177e4SLinus Torvalds 	}
34945cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
34955cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
34965cb2fc06SFUJITA Tomonori 		if (!open_devip) {
34971da177e4SLinus Torvalds 			printk(KERN_ERR "%s: out of memory at line %d\n",
3498cadbd4a5SHarvey Harrison 				__func__, __LINE__);
34991da177e4SLinus Torvalds 			return NULL;
35001da177e4SLinus Torvalds 		}
35011da177e4SLinus Torvalds 	}
3502a75869d1SFUJITA Tomonori 
35031da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
35041da177e4SLinus Torvalds 	open_devip->target = sdev->id;
35051da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
35061da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
3507cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
3508cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
3509c2248fc9SDouglas Gilbert 	open_devip->used = true;
35101da177e4SLinus Torvalds 	return open_devip;
35111da177e4SLinus Torvalds }
35121da177e4SLinus Torvalds 
35138dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
35141da177e4SLinus Torvalds {
35158dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
35169cb78c16SHannes Reinecke 		printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %llu>\n",
35178dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
351875ad23bcSNick Piggin 	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
35198dea0d02SFUJITA Tomonori 	return 0;
35208dea0d02SFUJITA Tomonori }
35211da177e4SLinus Torvalds 
35228dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
35238dea0d02SFUJITA Tomonori {
35248dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip;
3525a34c4e98SFUJITA Tomonori 
35261da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
35279cb78c16SHannes Reinecke 		printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %llu>\n",
35288dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
35298dea0d02SFUJITA Tomonori 	if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
35308dea0d02SFUJITA Tomonori 		sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
35318dea0d02SFUJITA Tomonori 	devip = devInfoReg(sdp);
35328dea0d02SFUJITA Tomonori 	if (NULL == devip)
35338dea0d02SFUJITA Tomonori 		return 1;	/* no resources, will be marked offline */
3534c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
35356bb5e6e7SAkinobu Mita 	blk_queue_max_segment_size(sdp->request_queue, -1U);
353678d4e5a0SDouglas Gilbert 	if (scsi_debug_no_uld)
353778d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
35388dea0d02SFUJITA Tomonori 	return 0;
35398dea0d02SFUJITA Tomonori }
35408dea0d02SFUJITA Tomonori 
35418dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
35428dea0d02SFUJITA Tomonori {
35438dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
35448dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
35458dea0d02SFUJITA Tomonori 
35468dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
35479cb78c16SHannes Reinecke 		printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %llu>\n",
35488dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
35498dea0d02SFUJITA Tomonori 	if (devip) {
355025985edcSLucas De Marchi 		/* make this slot available for re-use */
3551c2248fc9SDouglas Gilbert 		devip->used = false;
35528dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
35538dea0d02SFUJITA Tomonori 	}
35548dea0d02SFUJITA Tomonori }
35558dea0d02SFUJITA Tomonori 
3556cbf67842SDouglas Gilbert /* Returns 1 if cmnd found (deletes its timer or tasklet), else returns 0 */
35578dea0d02SFUJITA Tomonori static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
35588dea0d02SFUJITA Tomonori {
35598dea0d02SFUJITA Tomonori 	unsigned long iflags;
3560cbf67842SDouglas Gilbert 	int k, qmax, r_qmax;
35618dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3562cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
35638dea0d02SFUJITA Tomonori 
35648dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
3565cbf67842SDouglas Gilbert 	qmax = scsi_debug_max_queue;
3566cbf67842SDouglas Gilbert 	r_qmax = atomic_read(&retired_max_queue);
3567cbf67842SDouglas Gilbert 	if (r_qmax > qmax)
3568cbf67842SDouglas Gilbert 		qmax = r_qmax;
3569cbf67842SDouglas Gilbert 	for (k = 0; k < qmax; ++k) {
3570cbf67842SDouglas Gilbert 		if (test_bit(k, queued_in_use_bm)) {
35718dea0d02SFUJITA Tomonori 			sqcp = &queued_arr[k];
3572cbf67842SDouglas Gilbert 			if (cmnd == sqcp->a_cmnd) {
3573db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3574db525fceSDouglas Gilbert 					cmnd->device->hostdata;
3575db525fceSDouglas Gilbert 				if (devip)
3576db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3577db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3578db525fceSDouglas Gilbert 				spin_unlock_irqrestore(&queued_arr_lock,
3579db525fceSDouglas Gilbert 						       iflags);
3580cbf67842SDouglas Gilbert 				if (scsi_debug_ndelay > 0) {
3581cbf67842SDouglas Gilbert 					if (sqcp->sd_hrtp)
3582cbf67842SDouglas Gilbert 						hrtimer_cancel(
3583cbf67842SDouglas Gilbert 							&sqcp->sd_hrtp->hrt);
3584cbf67842SDouglas Gilbert 				} else if (scsi_debug_delay > 0) {
3585cbf67842SDouglas Gilbert 					if (sqcp->cmnd_timerp)
3586cbf67842SDouglas Gilbert 						del_timer_sync(
3587cbf67842SDouglas Gilbert 							sqcp->cmnd_timerp);
3588cbf67842SDouglas Gilbert 				} else if (scsi_debug_delay < 0) {
3589cbf67842SDouglas Gilbert 					if (sqcp->tletp)
3590cbf67842SDouglas Gilbert 						tasklet_kill(sqcp->tletp);
3591cbf67842SDouglas Gilbert 				}
3592db525fceSDouglas Gilbert 				clear_bit(k, queued_in_use_bm);
3593db525fceSDouglas Gilbert 				return 1;
35948dea0d02SFUJITA Tomonori 			}
35958dea0d02SFUJITA Tomonori 		}
3596cbf67842SDouglas Gilbert 	}
35978dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
3598db525fceSDouglas Gilbert 	return 0;
35998dea0d02SFUJITA Tomonori }
36008dea0d02SFUJITA Tomonori 
3601cbf67842SDouglas Gilbert /* Deletes (stops) timers or tasklets of all queued commands */
36028dea0d02SFUJITA Tomonori static void stop_all_queued(void)
36038dea0d02SFUJITA Tomonori {
36048dea0d02SFUJITA Tomonori 	unsigned long iflags;
36058dea0d02SFUJITA Tomonori 	int k;
36068dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3607cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
36088dea0d02SFUJITA Tomonori 
36098dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
3610cbf67842SDouglas Gilbert 	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3611cbf67842SDouglas Gilbert 		if (test_bit(k, queued_in_use_bm)) {
36128dea0d02SFUJITA Tomonori 			sqcp = &queued_arr[k];
3613cbf67842SDouglas Gilbert 			if (sqcp->a_cmnd) {
3614db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3615db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
3616db525fceSDouglas Gilbert 				if (devip)
3617db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3618db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3619db525fceSDouglas Gilbert 				spin_unlock_irqrestore(&queued_arr_lock,
3620db525fceSDouglas Gilbert 						       iflags);
3621cbf67842SDouglas Gilbert 				if (scsi_debug_ndelay > 0) {
3622cbf67842SDouglas Gilbert 					if (sqcp->sd_hrtp)
3623cbf67842SDouglas Gilbert 						hrtimer_cancel(
3624cbf67842SDouglas Gilbert 							&sqcp->sd_hrtp->hrt);
3625cbf67842SDouglas Gilbert 				} else if (scsi_debug_delay > 0) {
3626cbf67842SDouglas Gilbert 					if (sqcp->cmnd_timerp)
3627cbf67842SDouglas Gilbert 						del_timer_sync(
3628cbf67842SDouglas Gilbert 							sqcp->cmnd_timerp);
3629cbf67842SDouglas Gilbert 				} else if (scsi_debug_delay < 0) {
3630cbf67842SDouglas Gilbert 					if (sqcp->tletp)
3631cbf67842SDouglas Gilbert 						tasklet_kill(sqcp->tletp);
3632cbf67842SDouglas Gilbert 				}
3633db525fceSDouglas Gilbert 				clear_bit(k, queued_in_use_bm);
3634db525fceSDouglas Gilbert 				spin_lock_irqsave(&queued_arr_lock, iflags);
36358dea0d02SFUJITA Tomonori 			}
36368dea0d02SFUJITA Tomonori 		}
3637cbf67842SDouglas Gilbert 	}
3638cbf67842SDouglas Gilbert 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
3639cbf67842SDouglas Gilbert }
3640cbf67842SDouglas Gilbert 
3641cbf67842SDouglas Gilbert /* Free queued command memory on heap */
3642cbf67842SDouglas Gilbert static void free_all_queued(void)
3643cbf67842SDouglas Gilbert {
3644cbf67842SDouglas Gilbert 	unsigned long iflags;
3645cbf67842SDouglas Gilbert 	int k;
3646cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3647cbf67842SDouglas Gilbert 
3648cbf67842SDouglas Gilbert 	spin_lock_irqsave(&queued_arr_lock, iflags);
3649cbf67842SDouglas Gilbert 	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3650cbf67842SDouglas Gilbert 		sqcp = &queued_arr[k];
3651cbf67842SDouglas Gilbert 		kfree(sqcp->cmnd_timerp);
3652cbf67842SDouglas Gilbert 		sqcp->cmnd_timerp = NULL;
3653cbf67842SDouglas Gilbert 		kfree(sqcp->tletp);
3654cbf67842SDouglas Gilbert 		sqcp->tletp = NULL;
3655cbf67842SDouglas Gilbert 		kfree(sqcp->sd_hrtp);
3656cbf67842SDouglas Gilbert 		sqcp->sd_hrtp = NULL;
3657cbf67842SDouglas Gilbert 	}
36588dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
36591da177e4SLinus Torvalds }
36601da177e4SLinus Torvalds 
36611da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
36621da177e4SLinus Torvalds {
36631da177e4SLinus Torvalds 	++num_aborts;
3664cbf67842SDouglas Gilbert 	if (SCpnt) {
3665cbf67842SDouglas Gilbert 		if (SCpnt->device &&
3666cbf67842SDouglas Gilbert 		    (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts))
3667cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device, "%s\n",
3668cbf67842SDouglas Gilbert 				    __func__);
36691da177e4SLinus Torvalds 		stop_queued_cmnd(SCpnt);
3670cbf67842SDouglas Gilbert 	}
36711da177e4SLinus Torvalds 	return SUCCESS;
36721da177e4SLinus Torvalds }
36731da177e4SLinus Torvalds 
36741da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
36751da177e4SLinus Torvalds {
36761da177e4SLinus Torvalds 	struct sdebug_dev_info * devip;
36771da177e4SLinus Torvalds 
36781da177e4SLinus Torvalds 	++num_dev_resets;
3679cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
3680cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
3681cbf67842SDouglas Gilbert 
3682cbf67842SDouglas Gilbert 		if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)
3683cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3684cbf67842SDouglas Gilbert 		devip = devInfoReg(sdp);
36851da177e4SLinus Torvalds 		if (devip)
3686cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
36871da177e4SLinus Torvalds 	}
36881da177e4SLinus Torvalds 	return SUCCESS;
36891da177e4SLinus Torvalds }
36901da177e4SLinus Torvalds 
3691cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3692cbf67842SDouglas Gilbert {
3693cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
3694cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3695cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
3696cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
3697cbf67842SDouglas Gilbert 	int k = 0;
3698cbf67842SDouglas Gilbert 
3699cbf67842SDouglas Gilbert 	++num_target_resets;
3700cbf67842SDouglas Gilbert 	if (!SCpnt)
3701cbf67842SDouglas Gilbert 		goto lie;
3702cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
3703cbf67842SDouglas Gilbert 	if (!sdp)
3704cbf67842SDouglas Gilbert 		goto lie;
3705cbf67842SDouglas Gilbert 	if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)
3706cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3707cbf67842SDouglas Gilbert 	hp = sdp->host;
3708cbf67842SDouglas Gilbert 	if (!hp)
3709cbf67842SDouglas Gilbert 		goto lie;
3710cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3711cbf67842SDouglas Gilbert 	if (sdbg_host) {
3712cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
3713cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
3714cbf67842SDouglas Gilbert 				    dev_list)
3715cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
3716cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3717cbf67842SDouglas Gilbert 				++k;
3718cbf67842SDouglas Gilbert 			}
3719cbf67842SDouglas Gilbert 	}
3720cbf67842SDouglas Gilbert 	if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts)
3721cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3722cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
3723cbf67842SDouglas Gilbert lie:
3724cbf67842SDouglas Gilbert 	return SUCCESS;
3725cbf67842SDouglas Gilbert }
3726cbf67842SDouglas Gilbert 
37271da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
37281da177e4SLinus Torvalds {
37291da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
3730cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
37311da177e4SLinus Torvalds         struct scsi_device * sdp;
37321da177e4SLinus Torvalds         struct Scsi_Host * hp;
3733cbf67842SDouglas Gilbert 	int k = 0;
37341da177e4SLinus Torvalds 
37351da177e4SLinus Torvalds 	++num_bus_resets;
3736cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
3737cbf67842SDouglas Gilbert 		goto lie;
3738cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
3739cbf67842SDouglas Gilbert 	if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)
3740cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3741cbf67842SDouglas Gilbert 	hp = sdp->host;
3742cbf67842SDouglas Gilbert 	if (hp) {
3743d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
37441da177e4SLinus Torvalds 		if (sdbg_host) {
3745cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
37461da177e4SLinus Torvalds                                             &sdbg_host->dev_info_list,
3747cbf67842SDouglas Gilbert 					    dev_list) {
3748cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3749cbf67842SDouglas Gilbert 				++k;
37501da177e4SLinus Torvalds 			}
37511da177e4SLinus Torvalds 		}
3752cbf67842SDouglas Gilbert 	}
3753cbf67842SDouglas Gilbert 	if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts)
3754cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3755cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
3756cbf67842SDouglas Gilbert lie:
37571da177e4SLinus Torvalds 	return SUCCESS;
37581da177e4SLinus Torvalds }
37591da177e4SLinus Torvalds 
37601da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
37611da177e4SLinus Torvalds {
37621da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
3763cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3764cbf67842SDouglas Gilbert 	int k = 0;
37651da177e4SLinus Torvalds 
37661da177e4SLinus Torvalds 	++num_host_resets;
3767cbf67842SDouglas Gilbert 	if ((SCpnt->device) && (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts))
3768cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
37691da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
37701da177e4SLinus Torvalds         list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3771cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
3772cbf67842SDouglas Gilbert 				    dev_list) {
3773cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3774cbf67842SDouglas Gilbert 			++k;
3775cbf67842SDouglas Gilbert 		}
37761da177e4SLinus Torvalds         }
37771da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
37781da177e4SLinus Torvalds 	stop_all_queued();
3779cbf67842SDouglas Gilbert 	if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts)
3780cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
3781cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
37821da177e4SLinus Torvalds 	return SUCCESS;
37831da177e4SLinus Torvalds }
37841da177e4SLinus Torvalds 
3785f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
37865f2578e5SFUJITA Tomonori 				      unsigned long store_size)
37871da177e4SLinus Torvalds {
37881da177e4SLinus Torvalds 	struct partition * pp;
37891da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
37901da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
37911da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
37921da177e4SLinus Torvalds 
37931da177e4SLinus Torvalds 	/* assume partition table already zeroed */
3794f58b0efbSFUJITA Tomonori 	if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
37951da177e4SLinus Torvalds 		return;
37961da177e4SLinus Torvalds 	if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
37971da177e4SLinus Torvalds 		scsi_debug_num_parts = SDEBUG_MAX_PARTS;
3798cbf67842SDouglas Gilbert 		pr_warn("%s: reducing partitions to %d\n", __func__,
3799cbf67842SDouglas Gilbert 			SDEBUG_MAX_PARTS);
38001da177e4SLinus Torvalds 	}
3801c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
38021da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
38031da177e4SLinus Torvalds 			   / scsi_debug_num_parts;
38041da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
38051da177e4SLinus Torvalds         starts[0] = sdebug_sectors_per;
38061da177e4SLinus Torvalds 	for (k = 1; k < scsi_debug_num_parts; ++k)
38071da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
38081da177e4SLinus Torvalds 			    * heads_by_sects;
38091da177e4SLinus Torvalds 	starts[scsi_debug_num_parts] = num_sectors;
38101da177e4SLinus Torvalds 	starts[scsi_debug_num_parts + 1] = 0;
38111da177e4SLinus Torvalds 
38121da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
38131da177e4SLinus Torvalds 	ramp[511] = 0xAA;
38141da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
38151da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
38161da177e4SLinus Torvalds 		start_sec = starts[k];
38171da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
38181da177e4SLinus Torvalds 		pp->boot_ind = 0;
38191da177e4SLinus Torvalds 
38201da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
38211da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
38221da177e4SLinus Torvalds 			   / sdebug_sectors_per;
38231da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
38241da177e4SLinus Torvalds 
38251da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
38261da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
38271da177e4SLinus Torvalds 			       / sdebug_sectors_per;
38281da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
38291da177e4SLinus Torvalds 
3830150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
3831150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
38321da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
38331da177e4SLinus Torvalds 	}
38341da177e4SLinus Torvalds }
38351da177e4SLinus Torvalds 
3836cbf67842SDouglas Gilbert static int
3837cbf67842SDouglas Gilbert schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
3838cbf67842SDouglas Gilbert 	      int scsi_result, int delta_jiff)
38391da177e4SLinus Torvalds {
3840cbf67842SDouglas Gilbert 	unsigned long iflags;
3841cd62b7daSDouglas Gilbert 	int k, num_in_q, qdepth, inject;
3842cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp = NULL;
38431da177e4SLinus Torvalds 	struct scsi_device *sdp = cmnd->device;
38441da177e4SLinus Torvalds 
3845cbf67842SDouglas Gilbert 	if (NULL == cmnd || NULL == devip) {
3846cbf67842SDouglas Gilbert 		pr_warn("%s: called with NULL cmnd or devip pointer\n",
3847cbf67842SDouglas Gilbert 			__func__);
3848cbf67842SDouglas Gilbert 		/* no particularly good error to report back */
3849cbf67842SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
38501da177e4SLinus Torvalds 	}
3851cbf67842SDouglas Gilbert 	if ((scsi_result) && (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
3852cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
3853cbf67842SDouglas Gilbert 			    __func__, scsi_result);
3854cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
3855cd62b7daSDouglas Gilbert 		goto respond_in_thread;
38561da177e4SLinus Torvalds 
3857cd62b7daSDouglas Gilbert 	/* schedule the response at a later time if resources permit */
38581da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
3859cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
3860cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
3861cbf67842SDouglas Gilbert 	inject = 0;
3862cd62b7daSDouglas Gilbert 	if ((qdepth > 0) && (num_in_q >= qdepth)) {
3863cd62b7daSDouglas Gilbert 		if (scsi_result) {
3864cd62b7daSDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
3865cd62b7daSDouglas Gilbert 			goto respond_in_thread;
3866cd62b7daSDouglas Gilbert 		} else
3867cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
3868cd62b7daSDouglas Gilbert 	} else if ((scsi_debug_every_nth != 0) &&
3869cd62b7daSDouglas Gilbert 		   (SCSI_DEBUG_OPT_RARE_TSF & scsi_debug_opts) &&
3870cd62b7daSDouglas Gilbert 		   (scsi_result == 0)) {
3871cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
3872cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
3873cbf67842SDouglas Gilbert 		     abs(scsi_debug_every_nth))) {
3874cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
3875cbf67842SDouglas Gilbert 			inject = 1;
3876cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
38771da177e4SLinus Torvalds 		}
3878cbf67842SDouglas Gilbert 	}
3879cbf67842SDouglas Gilbert 
3880cd62b7daSDouglas Gilbert 	k = find_first_zero_bit(queued_in_use_bm, scsi_debug_max_queue);
388178d4e5a0SDouglas Gilbert 	if (k >= scsi_debug_max_queue) {
38821da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
3883cd62b7daSDouglas Gilbert 		if (scsi_result)
3884cd62b7daSDouglas Gilbert 			goto respond_in_thread;
3885cd62b7daSDouglas Gilbert 		else if (SCSI_DEBUG_OPT_ALL_TSF & scsi_debug_opts)
3886cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
3887cbf67842SDouglas Gilbert 		if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts)
3888cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
3889cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
3890cd62b7daSDouglas Gilbert 				    __func__, scsi_debug_max_queue,
3891cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
3892cbf67842SDouglas Gilbert 						    "report: host busy"));
3893cd62b7daSDouglas Gilbert 		if (scsi_result)
3894cd62b7daSDouglas Gilbert 			goto respond_in_thread;
3895cd62b7daSDouglas Gilbert 		else
3896cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
38971da177e4SLinus Torvalds 	}
3898cbf67842SDouglas Gilbert 	__set_bit(k, queued_in_use_bm);
3899cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
3900cbf67842SDouglas Gilbert 	sqcp = &queued_arr[k];
39011da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
3902cbf67842SDouglas Gilbert 	cmnd->result = scsi_result;
39031da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
3904cbf67842SDouglas Gilbert 	if (delta_jiff > 0) {
3905cbf67842SDouglas Gilbert 		if (NULL == sqcp->cmnd_timerp) {
3906cbf67842SDouglas Gilbert 			sqcp->cmnd_timerp = kmalloc(sizeof(struct timer_list),
3907cbf67842SDouglas Gilbert 						    GFP_ATOMIC);
3908cbf67842SDouglas Gilbert 			if (NULL == sqcp->cmnd_timerp)
3909cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
3910cbf67842SDouglas Gilbert 			init_timer(sqcp->cmnd_timerp);
3911cbf67842SDouglas Gilbert 		}
3912cbf67842SDouglas Gilbert 		sqcp->cmnd_timerp->function = sdebug_q_cmd_complete;
3913cbf67842SDouglas Gilbert 		sqcp->cmnd_timerp->data = k;
3914cbf67842SDouglas Gilbert 		sqcp->cmnd_timerp->expires = get_jiffies_64() + delta_jiff;
3915cbf67842SDouglas Gilbert 		add_timer(sqcp->cmnd_timerp);
3916cbf67842SDouglas Gilbert 	} else if (scsi_debug_ndelay > 0) {
3917cbf67842SDouglas Gilbert 		ktime_t kt = ktime_set(0, scsi_debug_ndelay);
3918cbf67842SDouglas Gilbert 		struct sdebug_hrtimer *sd_hp = sqcp->sd_hrtp;
3919cbf67842SDouglas Gilbert 
3920cbf67842SDouglas Gilbert 		if (NULL == sd_hp) {
3921cbf67842SDouglas Gilbert 			sd_hp = kmalloc(sizeof(*sd_hp), GFP_ATOMIC);
3922cbf67842SDouglas Gilbert 			if (NULL == sd_hp)
3923cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
3924cbf67842SDouglas Gilbert 			sqcp->sd_hrtp = sd_hp;
3925cbf67842SDouglas Gilbert 			hrtimer_init(&sd_hp->hrt, CLOCK_MONOTONIC,
3926cbf67842SDouglas Gilbert 				     HRTIMER_MODE_REL);
3927cbf67842SDouglas Gilbert 			sd_hp->hrt.function = sdebug_q_cmd_hrt_complete;
3928cbf67842SDouglas Gilbert 			sd_hp->qa_indx = k;
3929cbf67842SDouglas Gilbert 		}
3930cbf67842SDouglas Gilbert 		hrtimer_start(&sd_hp->hrt, kt, HRTIMER_MODE_REL);
3931cbf67842SDouglas Gilbert 	} else {	/* delay < 0 */
3932cbf67842SDouglas Gilbert 		if (NULL == sqcp->tletp) {
3933cbf67842SDouglas Gilbert 			sqcp->tletp = kmalloc(sizeof(*sqcp->tletp),
3934cbf67842SDouglas Gilbert 					      GFP_ATOMIC);
3935cbf67842SDouglas Gilbert 			if (NULL == sqcp->tletp)
3936cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
3937cbf67842SDouglas Gilbert 			tasklet_init(sqcp->tletp,
3938cbf67842SDouglas Gilbert 				     sdebug_q_cmd_complete, k);
3939cbf67842SDouglas Gilbert 		}
3940cbf67842SDouglas Gilbert 		if (-1 == delta_jiff)
3941cbf67842SDouglas Gilbert 			tasklet_hi_schedule(sqcp->tletp);
3942cbf67842SDouglas Gilbert 		else
3943cbf67842SDouglas Gilbert 			tasklet_schedule(sqcp->tletp);
3944cbf67842SDouglas Gilbert 	}
3945cd62b7daSDouglas Gilbert 	if ((SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) &&
3946cd62b7daSDouglas Gilbert 	    (scsi_result == device_qfull_result))
3947cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3948cbf67842SDouglas Gilbert 			    "%s: num_in_q=%d +1, %s%s\n", __func__,
3949cbf67842SDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""),
3950cbf67842SDouglas Gilbert 			    "status: TASK SET FULL");
39511da177e4SLinus Torvalds 	return 0;
3952cd62b7daSDouglas Gilbert 
3953cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
3954cd62b7daSDouglas Gilbert 	cmnd->result = scsi_result;
3955cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
3956cd62b7daSDouglas Gilbert 	return 0;
39571da177e4SLinus Torvalds }
3958cbf67842SDouglas Gilbert 
395923183910SDouglas Gilbert /* Note: The following macros create attribute files in the
396023183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
396123183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
396223183910SDouglas Gilbert    as it can when the corresponding attribute in the
396323183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
396423183910SDouglas Gilbert  */
3965c65b1445SDouglas Gilbert module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
39665b94e232SMartin K. Petersen module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
39670759c666SAkinobu Mita module_param_named(clustering, scsi_debug_clustering, bool, S_IRUGO | S_IWUSR);
3968c65b1445SDouglas Gilbert module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
3969c65b1445SDouglas Gilbert module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
39705b94e232SMartin K. Petersen module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
39715b94e232SMartin K. Petersen module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
3972c65b1445SDouglas Gilbert module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
3973c65b1445SDouglas Gilbert module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
397423183910SDouglas Gilbert module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
397568aee7baSAkinobu Mita module_param_named(guard, scsi_debug_guard, uint, S_IRUGO);
3976cbf67842SDouglas Gilbert module_param_named(host_lock, scsi_debug_host_lock, bool, S_IRUGO | S_IWUSR);
39775b94e232SMartin K. Petersen module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO);
39785b94e232SMartin K. Petersen module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO);
39795b94e232SMartin K. Petersen module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO);
3980be1dd78dSEric Sandeen module_param_named(lbprz, scsi_debug_lbprz, int, S_IRUGO);
39815b94e232SMartin K. Petersen module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
3982c65b1445SDouglas Gilbert module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
398378d4e5a0SDouglas Gilbert module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);
3984cbf67842SDouglas Gilbert module_param_named(ndelay, scsi_debug_ndelay, int, S_IRUGO | S_IWUSR);
3985c65b1445SDouglas Gilbert module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
398678d4e5a0SDouglas Gilbert module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);
3987c65b1445SDouglas Gilbert module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
3988c65b1445SDouglas Gilbert module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
39895b94e232SMartin K. Petersen module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO);
3990c65b1445SDouglas Gilbert module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
39915b94e232SMartin K. Petersen module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
3992c65b1445SDouglas Gilbert module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
3993d986788bSMartin Pitt module_param_named(removable, scsi_debug_removable, bool, S_IRUGO | S_IWUSR);
3994c65b1445SDouglas Gilbert module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
39955b94e232SMartin K. Petersen module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
3996c2248fc9SDouglas Gilbert module_param_named(strict, scsi_debug_strict, bool, S_IRUGO | S_IWUSR);
39975b94e232SMartin K. Petersen module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
39985b94e232SMartin K. Petersen module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
39995b94e232SMartin K. Petersen module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
40005b94e232SMartin K. Petersen module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
4001c65b1445SDouglas Gilbert module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
400223183910SDouglas Gilbert module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
400323183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
40045b94e232SMartin K. Petersen module_param_named(write_same_length, scsi_debug_write_same_length, int,
40055b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
40061da177e4SLinus Torvalds 
40071da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
40081da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
40091da177e4SLinus Torvalds MODULE_LICENSE("GPL");
40101da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION);
40111da177e4SLinus Torvalds 
40121da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
40135b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
40140759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
4015cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
4016c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
40175b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
40185b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
4019c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
4020beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
402123183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
40225b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
4023cbf67842SDouglas Gilbert MODULE_PARM_DESC(host_lock, "use host_lock around all commands (def=0)");
40245b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
40255b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
40265b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
4027be1dd78dSEric Sandeen MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
40285b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
4029c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
4030cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4031cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
4032c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
403378d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
40341da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
4035c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
40365b94e232SMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
40376f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
40385b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
40391da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
4040d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
4041e46b0344SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])");
4042ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
4043c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
40445b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
40455b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
40466014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
40476014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
4048c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
40495b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
40505b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
40511da177e4SLinus Torvalds 
40521da177e4SLinus Torvalds static char sdebug_info[256];
40531da177e4SLinus Torvalds 
40541da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp)
40551da177e4SLinus Torvalds {
40561da177e4SLinus Torvalds 	sprintf(sdebug_info, "scsi_debug, version %s [%s], "
40571da177e4SLinus Torvalds 		"dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
40581da177e4SLinus Torvalds 		scsi_debug_version_date, scsi_debug_dev_size_mb,
40591da177e4SLinus Torvalds 		scsi_debug_opts);
40601da177e4SLinus Torvalds 	return sdebug_info;
40611da177e4SLinus Torvalds }
40621da177e4SLinus Torvalds 
4063cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
4064c8ed555aSAl Viro static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, int length)
40651da177e4SLinus Torvalds {
40661da177e4SLinus Torvalds 	char arr[16];
4067c8ed555aSAl Viro 	int opts;
40681da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
40691da177e4SLinus Torvalds 
40701da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
40711da177e4SLinus Torvalds 		return -EACCES;
40721da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
40731da177e4SLinus Torvalds 	arr[minLen] = '\0';
4074c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
40751da177e4SLinus Torvalds 		return -EINVAL;
4076c8ed555aSAl Viro 	scsi_debug_opts = opts;
40771da177e4SLinus Torvalds 	if (scsi_debug_every_nth != 0)
4078cbf67842SDouglas Gilbert 		atomic_set(&sdebug_cmnd_count, 0);
40791da177e4SLinus Torvalds 	return length;
40801da177e4SLinus Torvalds }
4081c8ed555aSAl Viro 
4082cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4083cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
4084cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
4085c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4086c8ed555aSAl Viro {
4087cbf67842SDouglas Gilbert 	int f, l;
4088cbf67842SDouglas Gilbert 	char b[32];
4089cbf67842SDouglas Gilbert 
4090cbf67842SDouglas Gilbert 	if (scsi_debug_every_nth > 0)
4091cbf67842SDouglas Gilbert 		snprintf(b, sizeof(b), " (curr:%d)",
4092cbf67842SDouglas Gilbert 			 ((SCSI_DEBUG_OPT_RARE_TSF & scsi_debug_opts) ?
4093cbf67842SDouglas Gilbert 				atomic_read(&sdebug_a_tsf) :
4094cbf67842SDouglas Gilbert 				atomic_read(&sdebug_cmnd_count)));
4095cbf67842SDouglas Gilbert 	else
4096cbf67842SDouglas Gilbert 		b[0] = '\0';
4097cbf67842SDouglas Gilbert 
4098cbf67842SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n"
40991da177e4SLinus Torvalds 		"num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
4100cbf67842SDouglas Gilbert 		"every_nth=%d%s\n"
4101cbf67842SDouglas Gilbert 		"delay=%d, ndelay=%d, max_luns=%d, q_completions=%d\n"
41021da177e4SLinus Torvalds 		"sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
4103cbf67842SDouglas Gilbert 		"command aborts=%d; RESETs: device=%d, target=%d, bus=%d, "
4104cbf67842SDouglas Gilbert 		"host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d "
4105cbf67842SDouglas Gilbert 		"usec_in_jiffy=%lu\n",
4106cbf67842SDouglas Gilbert 		SCSI_DEBUG_VERSION, scsi_debug_version_date,
4107cbf67842SDouglas Gilbert 		scsi_debug_num_tgts, scsi_debug_dev_size_mb, scsi_debug_opts,
4108cbf67842SDouglas Gilbert 		scsi_debug_every_nth, b, scsi_debug_delay, scsi_debug_ndelay,
4109cbf67842SDouglas Gilbert 		scsi_debug_max_luns, atomic_read(&sdebug_completions),
4110597136abSMartin K. Petersen 		scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
4111cbf67842SDouglas Gilbert 		sdebug_sectors_per, num_aborts, num_dev_resets,
4112cbf67842SDouglas Gilbert 		num_target_resets, num_bus_resets, num_host_resets,
4113cbf67842SDouglas Gilbert 		dix_reads, dix_writes, dif_errors, TICK_NSEC / 1000);
4114cbf67842SDouglas Gilbert 
4115cbf67842SDouglas Gilbert 	f = find_first_bit(queued_in_use_bm, scsi_debug_max_queue);
4116cbf67842SDouglas Gilbert 	if (f != scsi_debug_max_queue) {
4117cbf67842SDouglas Gilbert 		l = find_last_bit(queued_in_use_bm, scsi_debug_max_queue);
4118cbf67842SDouglas Gilbert 		seq_printf(m, "   %s BUSY: first,last bits set: %d,%d\n",
4119cbf67842SDouglas Gilbert 			   "queued_in_use_bm", f, l);
4120cbf67842SDouglas Gilbert 	}
4121c8ed555aSAl Viro 	return 0;
41221da177e4SLinus Torvalds }
41231da177e4SLinus Torvalds 
412482069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
41251da177e4SLinus Torvalds {
41261da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
41271da177e4SLinus Torvalds }
4128cbf67842SDouglas Gilbert /* Returns -EBUSY if delay is being changed and commands are queued */
412982069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
413082069379SAkinobu Mita 			   size_t count)
41311da177e4SLinus Torvalds {
4132cbf67842SDouglas Gilbert 	int delay, res;
41331da177e4SLinus Torvalds 
4134cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &delay))) {
4135cbf67842SDouglas Gilbert 		res = count;
4136cbf67842SDouglas Gilbert 		if (scsi_debug_delay != delay) {
4137cbf67842SDouglas Gilbert 			unsigned long iflags;
4138cbf67842SDouglas Gilbert 			int k;
4139cbf67842SDouglas Gilbert 
4140cbf67842SDouglas Gilbert 			spin_lock_irqsave(&queued_arr_lock, iflags);
4141cbf67842SDouglas Gilbert 			k = find_first_bit(queued_in_use_bm,
4142cbf67842SDouglas Gilbert 					   scsi_debug_max_queue);
4143cbf67842SDouglas Gilbert 			if (k != scsi_debug_max_queue)
4144cbf67842SDouglas Gilbert 				res = -EBUSY;	/* have queued commands */
4145cbf67842SDouglas Gilbert 			else {
41461da177e4SLinus Torvalds 				scsi_debug_delay = delay;
4147cbf67842SDouglas Gilbert 				scsi_debug_ndelay = 0;
41481da177e4SLinus Torvalds 			}
4149cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
4150cbf67842SDouglas Gilbert 		}
4151cbf67842SDouglas Gilbert 		return res;
41521da177e4SLinus Torvalds 	}
41531da177e4SLinus Torvalds 	return -EINVAL;
41541da177e4SLinus Torvalds }
415582069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
41561da177e4SLinus Torvalds 
4157cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4158cbf67842SDouglas Gilbert {
4159cbf67842SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ndelay);
4160cbf67842SDouglas Gilbert }
4161cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
4162cbf67842SDouglas Gilbert /* If > 0 and accepted then scsi_debug_delay is set to DELAY_OVERRIDDEN */
4163cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
4164cbf67842SDouglas Gilbert 			   size_t count)
4165cbf67842SDouglas Gilbert {
4166cbf67842SDouglas Gilbert 	unsigned long iflags;
4167cbf67842SDouglas Gilbert 	int ndelay, res, k;
4168cbf67842SDouglas Gilbert 
4169cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4170cbf67842SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < 1000000000)) {
4171cbf67842SDouglas Gilbert 		res = count;
4172cbf67842SDouglas Gilbert 		if (scsi_debug_ndelay != ndelay) {
4173cbf67842SDouglas Gilbert 			spin_lock_irqsave(&queued_arr_lock, iflags);
4174cbf67842SDouglas Gilbert 			k = find_first_bit(queued_in_use_bm,
4175cbf67842SDouglas Gilbert 					   scsi_debug_max_queue);
4176cbf67842SDouglas Gilbert 			if (k != scsi_debug_max_queue)
4177cbf67842SDouglas Gilbert 				res = -EBUSY;	/* have queued commands */
4178cbf67842SDouglas Gilbert 			else {
4179cbf67842SDouglas Gilbert 				scsi_debug_ndelay = ndelay;
4180cbf67842SDouglas Gilbert 				scsi_debug_delay = ndelay ? DELAY_OVERRIDDEN
4181cbf67842SDouglas Gilbert 							  : DEF_DELAY;
4182cbf67842SDouglas Gilbert 			}
4183cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
4184cbf67842SDouglas Gilbert 		}
4185cbf67842SDouglas Gilbert 		return res;
4186cbf67842SDouglas Gilbert 	}
4187cbf67842SDouglas Gilbert 	return -EINVAL;
4188cbf67842SDouglas Gilbert }
4189cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
4190cbf67842SDouglas Gilbert 
419182069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
41921da177e4SLinus Torvalds {
41931da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
41941da177e4SLinus Torvalds }
41951da177e4SLinus Torvalds 
419682069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
419782069379SAkinobu Mita 			  size_t count)
41981da177e4SLinus Torvalds {
41991da177e4SLinus Torvalds         int opts;
42001da177e4SLinus Torvalds 	char work[20];
42011da177e4SLinus Torvalds 
42021da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
420348a96876SRasmus Villemoes 		if (0 == strncasecmp(work,"0x", 2)) {
42041da177e4SLinus Torvalds 			if (1 == sscanf(&work[2], "%x", &opts))
42051da177e4SLinus Torvalds 				goto opts_done;
42061da177e4SLinus Torvalds 		} else {
42071da177e4SLinus Torvalds 			if (1 == sscanf(work, "%d", &opts))
42081da177e4SLinus Torvalds 				goto opts_done;
42091da177e4SLinus Torvalds 		}
42101da177e4SLinus Torvalds 	}
42111da177e4SLinus Torvalds 	return -EINVAL;
42121da177e4SLinus Torvalds opts_done:
42131da177e4SLinus Torvalds 	scsi_debug_opts = opts;
4214817fd66bSDouglas Gilbert 	if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts)
4215817fd66bSDouglas Gilbert 		sdebug_any_injecting_opt = true;
4216817fd66bSDouglas Gilbert 	else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts)
4217817fd66bSDouglas Gilbert 		sdebug_any_injecting_opt = true;
4218817fd66bSDouglas Gilbert 	else if (SCSI_DEBUG_OPT_DIF_ERR & opts)
4219817fd66bSDouglas Gilbert 		sdebug_any_injecting_opt = true;
4220817fd66bSDouglas Gilbert 	else if (SCSI_DEBUG_OPT_DIX_ERR & opts)
4221817fd66bSDouglas Gilbert 		sdebug_any_injecting_opt = true;
4222817fd66bSDouglas Gilbert 	else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts)
4223817fd66bSDouglas Gilbert 		sdebug_any_injecting_opt = true;
4224cbf67842SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
4225cbf67842SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
42261da177e4SLinus Torvalds 	return count;
42271da177e4SLinus Torvalds }
422882069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
42291da177e4SLinus Torvalds 
423082069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
42311da177e4SLinus Torvalds {
42321da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
42331da177e4SLinus Torvalds }
423482069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
423582069379SAkinobu Mita 			   size_t count)
42361da177e4SLinus Torvalds {
42371da177e4SLinus Torvalds         int n;
42381da177e4SLinus Torvalds 
42391da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
42401da177e4SLinus Torvalds 		scsi_debug_ptype = n;
42411da177e4SLinus Torvalds 		return count;
42421da177e4SLinus Torvalds 	}
42431da177e4SLinus Torvalds 	return -EINVAL;
42441da177e4SLinus Torvalds }
424582069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
42461da177e4SLinus Torvalds 
424782069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
42481da177e4SLinus Torvalds {
42491da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
42501da177e4SLinus Torvalds }
425182069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
425282069379SAkinobu Mita 			    size_t count)
42531da177e4SLinus Torvalds {
42541da177e4SLinus Torvalds         int n;
42551da177e4SLinus Torvalds 
42561da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
42571da177e4SLinus Torvalds 		scsi_debug_dsense = n;
42581da177e4SLinus Torvalds 		return count;
42591da177e4SLinus Torvalds 	}
42601da177e4SLinus Torvalds 	return -EINVAL;
42611da177e4SLinus Torvalds }
426282069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
42631da177e4SLinus Torvalds 
426482069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
426523183910SDouglas Gilbert {
426623183910SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
426723183910SDouglas Gilbert }
426882069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
426982069379SAkinobu Mita 			     size_t count)
427023183910SDouglas Gilbert {
427123183910SDouglas Gilbert         int n;
427223183910SDouglas Gilbert 
427323183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4274cbf67842SDouglas Gilbert 		n = (n > 0);
4275cbf67842SDouglas Gilbert 		scsi_debug_fake_rw = (scsi_debug_fake_rw > 0);
4276cbf67842SDouglas Gilbert 		if (scsi_debug_fake_rw != n) {
4277cbf67842SDouglas Gilbert 			if ((0 == n) && (NULL == fake_storep)) {
4278cbf67842SDouglas Gilbert 				unsigned long sz =
4279cbf67842SDouglas Gilbert 					(unsigned long)scsi_debug_dev_size_mb *
4280cbf67842SDouglas Gilbert 					1048576;
4281cbf67842SDouglas Gilbert 
4282cbf67842SDouglas Gilbert 				fake_storep = vmalloc(sz);
4283cbf67842SDouglas Gilbert 				if (NULL == fake_storep) {
4284cbf67842SDouglas Gilbert 					pr_err("%s: out of memory, 9\n",
4285cbf67842SDouglas Gilbert 					       __func__);
4286cbf67842SDouglas Gilbert 					return -ENOMEM;
4287cbf67842SDouglas Gilbert 				}
4288cbf67842SDouglas Gilbert 				memset(fake_storep, 0, sz);
4289cbf67842SDouglas Gilbert 			}
429023183910SDouglas Gilbert 			scsi_debug_fake_rw = n;
4291cbf67842SDouglas Gilbert 		}
429223183910SDouglas Gilbert 		return count;
429323183910SDouglas Gilbert 	}
429423183910SDouglas Gilbert 	return -EINVAL;
429523183910SDouglas Gilbert }
429682069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
429723183910SDouglas Gilbert 
429882069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
4299c65b1445SDouglas Gilbert {
4300c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
4301c65b1445SDouglas Gilbert }
430282069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
430382069379SAkinobu Mita 			      size_t count)
4304c65b1445SDouglas Gilbert {
4305c65b1445SDouglas Gilbert         int n;
4306c65b1445SDouglas Gilbert 
4307c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4308c65b1445SDouglas Gilbert 		scsi_debug_no_lun_0 = n;
4309c65b1445SDouglas Gilbert 		return count;
4310c65b1445SDouglas Gilbert 	}
4311c65b1445SDouglas Gilbert 	return -EINVAL;
4312c65b1445SDouglas Gilbert }
431382069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
4314c65b1445SDouglas Gilbert 
431582069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
43161da177e4SLinus Torvalds {
43171da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
43181da177e4SLinus Torvalds }
431982069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
432082069379SAkinobu Mita 			      size_t count)
43211da177e4SLinus Torvalds {
43221da177e4SLinus Torvalds         int n;
43231da177e4SLinus Torvalds 
43241da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
43251da177e4SLinus Torvalds 		scsi_debug_num_tgts = n;
43261da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
43271da177e4SLinus Torvalds 		return count;
43281da177e4SLinus Torvalds 	}
43291da177e4SLinus Torvalds 	return -EINVAL;
43301da177e4SLinus Torvalds }
433182069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
43321da177e4SLinus Torvalds 
433382069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
43341da177e4SLinus Torvalds {
43351da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
43361da177e4SLinus Torvalds }
433782069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
43381da177e4SLinus Torvalds 
433982069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
43401da177e4SLinus Torvalds {
43411da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
43421da177e4SLinus Torvalds }
434382069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
43441da177e4SLinus Torvalds 
434582069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
43461da177e4SLinus Torvalds {
43471da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
43481da177e4SLinus Torvalds }
434982069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
435082069379SAkinobu Mita 			       size_t count)
43511da177e4SLinus Torvalds {
43521da177e4SLinus Torvalds         int nth;
43531da177e4SLinus Torvalds 
43541da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
43551da177e4SLinus Torvalds 		scsi_debug_every_nth = nth;
4356cbf67842SDouglas Gilbert 		atomic_set(&sdebug_cmnd_count, 0);
43571da177e4SLinus Torvalds 		return count;
43581da177e4SLinus Torvalds 	}
43591da177e4SLinus Torvalds 	return -EINVAL;
43601da177e4SLinus Torvalds }
436182069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
43621da177e4SLinus Torvalds 
436382069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
43641da177e4SLinus Torvalds {
43651da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
43661da177e4SLinus Torvalds }
436782069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
436882069379SAkinobu Mita 			      size_t count)
43691da177e4SLinus Torvalds {
43701da177e4SLinus Torvalds         int n;
43711da177e4SLinus Torvalds 
43721da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
43731da177e4SLinus Torvalds 		scsi_debug_max_luns = n;
43741da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
43751da177e4SLinus Torvalds 		return count;
43761da177e4SLinus Torvalds 	}
43771da177e4SLinus Torvalds 	return -EINVAL;
43781da177e4SLinus Torvalds }
437982069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
43801da177e4SLinus Torvalds 
438182069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
438278d4e5a0SDouglas Gilbert {
438378d4e5a0SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue);
438478d4e5a0SDouglas Gilbert }
4385cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
4386cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
438782069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
438882069379SAkinobu Mita 			       size_t count)
438978d4e5a0SDouglas Gilbert {
4390cbf67842SDouglas Gilbert 	unsigned long iflags;
4391cbf67842SDouglas Gilbert 	int n, k;
439278d4e5a0SDouglas Gilbert 
439378d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
439478d4e5a0SDouglas Gilbert 	    (n <= SCSI_DEBUG_CANQUEUE)) {
4395cbf67842SDouglas Gilbert 		spin_lock_irqsave(&queued_arr_lock, iflags);
4396cbf67842SDouglas Gilbert 		k = find_last_bit(queued_in_use_bm, SCSI_DEBUG_CANQUEUE);
439778d4e5a0SDouglas Gilbert 		scsi_debug_max_queue = n;
4398cbf67842SDouglas Gilbert 		if (SCSI_DEBUG_CANQUEUE == k)
4399cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4400cbf67842SDouglas Gilbert 		else if (k >= n)
4401cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4402cbf67842SDouglas Gilbert 		else
4403cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4404cbf67842SDouglas Gilbert 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
440578d4e5a0SDouglas Gilbert 		return count;
440678d4e5a0SDouglas Gilbert 	}
440778d4e5a0SDouglas Gilbert 	return -EINVAL;
440878d4e5a0SDouglas Gilbert }
440982069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
441078d4e5a0SDouglas Gilbert 
441182069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
441278d4e5a0SDouglas Gilbert {
441378d4e5a0SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld);
441478d4e5a0SDouglas Gilbert }
441582069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
441678d4e5a0SDouglas Gilbert 
441782069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
44181da177e4SLinus Torvalds {
44191da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
44201da177e4SLinus Torvalds }
442182069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
44221da177e4SLinus Torvalds 
442382069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
4424c65b1445SDouglas Gilbert {
4425c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
4426c65b1445SDouglas Gilbert }
442782069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
442882069379SAkinobu Mita 				size_t count)
4429c65b1445SDouglas Gilbert {
4430c65b1445SDouglas Gilbert         int n;
44310d01c5dfSDouglas Gilbert 	bool changed;
4432c65b1445SDouglas Gilbert 
4433c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
44340d01c5dfSDouglas Gilbert 		changed = (scsi_debug_virtual_gb != n);
4435c65b1445SDouglas Gilbert 		scsi_debug_virtual_gb = n;
443628898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
44370d01c5dfSDouglas Gilbert 		if (changed) {
44380d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
44390d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
444028898873SFUJITA Tomonori 
44410d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
44420d01c5dfSDouglas Gilbert 					    host_list) {
44430d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
44440d01c5dfSDouglas Gilbert 						    dev_list) {
44450d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
44460d01c5dfSDouglas Gilbert 						dp->uas_bm);
44470d01c5dfSDouglas Gilbert 				}
44480d01c5dfSDouglas Gilbert 			}
44490d01c5dfSDouglas Gilbert 		}
4450c65b1445SDouglas Gilbert 		return count;
4451c65b1445SDouglas Gilbert 	}
4452c65b1445SDouglas Gilbert 	return -EINVAL;
4453c65b1445SDouglas Gilbert }
445482069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
4455c65b1445SDouglas Gilbert 
445682069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
44571da177e4SLinus Torvalds {
44581da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
44591da177e4SLinus Torvalds }
44601da177e4SLinus Torvalds 
446182069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
446282069379SAkinobu Mita 			      size_t count)
44631da177e4SLinus Torvalds {
44641da177e4SLinus Torvalds 	int delta_hosts;
44651da177e4SLinus Torvalds 
4466f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
44671da177e4SLinus Torvalds 		return -EINVAL;
44681da177e4SLinus Torvalds 	if (delta_hosts > 0) {
44691da177e4SLinus Torvalds 		do {
44701da177e4SLinus Torvalds 			sdebug_add_adapter();
44711da177e4SLinus Torvalds 		} while (--delta_hosts);
44721da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
44731da177e4SLinus Torvalds 		do {
44741da177e4SLinus Torvalds 			sdebug_remove_adapter();
44751da177e4SLinus Torvalds 		} while (++delta_hosts);
44761da177e4SLinus Torvalds 	}
44771da177e4SLinus Torvalds 	return count;
44781da177e4SLinus Torvalds }
447982069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
44801da177e4SLinus Torvalds 
448182069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
448223183910SDouglas Gilbert {
448323183910SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
448423183910SDouglas Gilbert }
448582069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
448682069379SAkinobu Mita 				    size_t count)
448723183910SDouglas Gilbert {
448823183910SDouglas Gilbert 	int n;
448923183910SDouglas Gilbert 
449023183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
449123183910SDouglas Gilbert 		scsi_debug_vpd_use_hostno = n;
449223183910SDouglas Gilbert 		return count;
449323183910SDouglas Gilbert 	}
449423183910SDouglas Gilbert 	return -EINVAL;
449523183910SDouglas Gilbert }
449682069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
449723183910SDouglas Gilbert 
449882069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
4499597136abSMartin K. Petersen {
4500597136abSMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
4501597136abSMartin K. Petersen }
450282069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
4503597136abSMartin K. Petersen 
450482069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
4505c6a44287SMartin K. Petersen {
4506c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
4507c6a44287SMartin K. Petersen }
450882069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
4509c6a44287SMartin K. Petersen 
451082069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
4511c6a44287SMartin K. Petersen {
4512c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
4513c6a44287SMartin K. Petersen }
451482069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
4515c6a44287SMartin K. Petersen 
451682069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
4517c6a44287SMartin K. Petersen {
451868aee7baSAkinobu Mita 	return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_guard);
4519c6a44287SMartin K. Petersen }
452082069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
4521c6a44287SMartin K. Petersen 
452282069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
4523c6a44287SMartin K. Petersen {
4524c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
4525c6a44287SMartin K. Petersen }
452682069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
4527c6a44287SMartin K. Petersen 
452882069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
452944d92694SMartin K. Petersen {
453044d92694SMartin K. Petersen 	ssize_t count;
453144d92694SMartin K. Petersen 
45325b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
453344d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
453444d92694SMartin K. Petersen 				 sdebug_store_sectors);
453544d92694SMartin K. Petersen 
453644d92694SMartin K. Petersen 	count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
453744d92694SMartin K. Petersen 
453844d92694SMartin K. Petersen 	buf[count++] = '\n';
453944d92694SMartin K. Petersen 	buf[count++] = 0;
454044d92694SMartin K. Petersen 
454144d92694SMartin K. Petersen 	return count;
454244d92694SMartin K. Petersen }
454382069379SAkinobu Mita static DRIVER_ATTR_RO(map);
454444d92694SMartin K. Petersen 
454582069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
4546d986788bSMartin Pitt {
4547d986788bSMartin Pitt 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_removable ? 1 : 0);
4548d986788bSMartin Pitt }
454982069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
455082069379SAkinobu Mita 			       size_t count)
4551d986788bSMartin Pitt {
4552d986788bSMartin Pitt 	int n;
4553d986788bSMartin Pitt 
4554d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4555d986788bSMartin Pitt 		scsi_debug_removable = (n > 0);
4556d986788bSMartin Pitt 		return count;
4557d986788bSMartin Pitt 	}
4558d986788bSMartin Pitt 	return -EINVAL;
4559d986788bSMartin Pitt }
456082069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
4561d986788bSMartin Pitt 
4562cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4563cbf67842SDouglas Gilbert {
4564cbf67842SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!scsi_debug_host_lock);
4565cbf67842SDouglas Gilbert }
4566cbf67842SDouglas Gilbert /* Returns -EBUSY if host_lock is being changed and commands are queued */
4567cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4568cbf67842SDouglas Gilbert 			       size_t count)
4569cbf67842SDouglas Gilbert {
4570cbf67842SDouglas Gilbert 	int n, res;
4571cbf67842SDouglas Gilbert 
4572cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4573cbf67842SDouglas Gilbert 		bool new_host_lock = (n > 0);
4574cbf67842SDouglas Gilbert 
4575cbf67842SDouglas Gilbert 		res = count;
4576cbf67842SDouglas Gilbert 		if (new_host_lock != scsi_debug_host_lock) {
4577cbf67842SDouglas Gilbert 			unsigned long iflags;
4578cbf67842SDouglas Gilbert 			int k;
4579cbf67842SDouglas Gilbert 
4580cbf67842SDouglas Gilbert 			spin_lock_irqsave(&queued_arr_lock, iflags);
4581cbf67842SDouglas Gilbert 			k = find_first_bit(queued_in_use_bm,
4582cbf67842SDouglas Gilbert 					   scsi_debug_max_queue);
4583cbf67842SDouglas Gilbert 			if (k != scsi_debug_max_queue)
4584cbf67842SDouglas Gilbert 				res = -EBUSY;	/* have queued commands */
4585cbf67842SDouglas Gilbert 			else
4586cbf67842SDouglas Gilbert 				scsi_debug_host_lock = new_host_lock;
4587cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
4588cbf67842SDouglas Gilbert 		}
4589cbf67842SDouglas Gilbert 		return res;
4590cbf67842SDouglas Gilbert 	}
4591cbf67842SDouglas Gilbert 	return -EINVAL;
4592cbf67842SDouglas Gilbert }
4593cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
4594cbf67842SDouglas Gilbert 
4595c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
4596c2248fc9SDouglas Gilbert {
4597c2248fc9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!scsi_debug_strict);
4598c2248fc9SDouglas Gilbert }
4599c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4600c2248fc9SDouglas Gilbert 			    size_t count)
4601c2248fc9SDouglas Gilbert {
4602c2248fc9SDouglas Gilbert 	int n;
4603c2248fc9SDouglas Gilbert 
4604c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4605c2248fc9SDouglas Gilbert 		scsi_debug_strict = (n > 0);
4606c2248fc9SDouglas Gilbert 		return count;
4607c2248fc9SDouglas Gilbert 	}
4608c2248fc9SDouglas Gilbert 	return -EINVAL;
4609c2248fc9SDouglas Gilbert }
4610c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
4611c2248fc9SDouglas Gilbert 
4612cbf67842SDouglas Gilbert 
461382069379SAkinobu Mita /* Note: The following array creates attribute files in the
461423183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
461523183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
461623183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
461723183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
461823183910SDouglas Gilbert  */
46196ecaff7fSRandy Dunlap 
462082069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
462182069379SAkinobu Mita 	&driver_attr_delay.attr,
462282069379SAkinobu Mita 	&driver_attr_opts.attr,
462382069379SAkinobu Mita 	&driver_attr_ptype.attr,
462482069379SAkinobu Mita 	&driver_attr_dsense.attr,
462582069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
462682069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
462782069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
462882069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
462982069379SAkinobu Mita 	&driver_attr_num_parts.attr,
463082069379SAkinobu Mita 	&driver_attr_every_nth.attr,
463182069379SAkinobu Mita 	&driver_attr_max_luns.attr,
463282069379SAkinobu Mita 	&driver_attr_max_queue.attr,
463382069379SAkinobu Mita 	&driver_attr_no_uld.attr,
463482069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
463582069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
463682069379SAkinobu Mita 	&driver_attr_add_host.attr,
463782069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
463882069379SAkinobu Mita 	&driver_attr_sector_size.attr,
463982069379SAkinobu Mita 	&driver_attr_dix.attr,
464082069379SAkinobu Mita 	&driver_attr_dif.attr,
464182069379SAkinobu Mita 	&driver_attr_guard.attr,
464282069379SAkinobu Mita 	&driver_attr_ato.attr,
464382069379SAkinobu Mita 	&driver_attr_map.attr,
464482069379SAkinobu Mita 	&driver_attr_removable.attr,
4645cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
4646cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
4647c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
464882069379SAkinobu Mita 	NULL,
464982069379SAkinobu Mita };
465082069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
46511da177e4SLinus Torvalds 
465211ddcecaSAkinobu Mita static struct device *pseudo_primary;
46538dea0d02SFUJITA Tomonori 
46541da177e4SLinus Torvalds static int __init scsi_debug_init(void)
46551da177e4SLinus Torvalds {
46565f2578e5SFUJITA Tomonori 	unsigned long sz;
46571da177e4SLinus Torvalds 	int host_to_add;
46581da177e4SLinus Torvalds 	int k;
46596ecaff7fSRandy Dunlap 	int ret;
46601da177e4SLinus Torvalds 
4661cbf67842SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
4662cbf67842SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
4663cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
4664cbf67842SDouglas Gilbert 
4665cbf67842SDouglas Gilbert 	if (scsi_debug_ndelay >= 1000000000) {
4666cbf67842SDouglas Gilbert 		pr_warn("%s: ndelay must be less than 1 second, ignored\n",
4667cbf67842SDouglas Gilbert 			__func__);
4668cbf67842SDouglas Gilbert 		scsi_debug_ndelay = 0;
4669cbf67842SDouglas Gilbert 	} else if (scsi_debug_ndelay > 0)
4670cbf67842SDouglas Gilbert 		scsi_debug_delay = DELAY_OVERRIDDEN;
4671cbf67842SDouglas Gilbert 
4672597136abSMartin K. Petersen 	switch (scsi_debug_sector_size) {
4673597136abSMartin K. Petersen 	case  512:
4674597136abSMartin K. Petersen 	case 1024:
4675597136abSMartin K. Petersen 	case 2048:
4676597136abSMartin K. Petersen 	case 4096:
4677597136abSMartin K. Petersen 		break;
4678597136abSMartin K. Petersen 	default:
4679cbf67842SDouglas Gilbert 		pr_err("%s: invalid sector_size %d\n", __func__,
4680597136abSMartin K. Petersen 		       scsi_debug_sector_size);
4681597136abSMartin K. Petersen 		return -EINVAL;
4682597136abSMartin K. Petersen 	}
4683597136abSMartin K. Petersen 
4684c6a44287SMartin K. Petersen 	switch (scsi_debug_dif) {
4685c6a44287SMartin K. Petersen 
4686c6a44287SMartin K. Petersen 	case SD_DIF_TYPE0_PROTECTION:
4687c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
4688395cef03SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
4689c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
4690c6a44287SMartin K. Petersen 		break;
4691c6a44287SMartin K. Petersen 
4692c6a44287SMartin K. Petersen 	default:
4693cbf67842SDouglas Gilbert 		pr_err("%s: dif must be 0, 1, 2 or 3\n", __func__);
4694c6a44287SMartin K. Petersen 		return -EINVAL;
4695c6a44287SMartin K. Petersen 	}
4696c6a44287SMartin K. Petersen 
4697c6a44287SMartin K. Petersen 	if (scsi_debug_guard > 1) {
4698cbf67842SDouglas Gilbert 		pr_err("%s: guard must be 0 or 1\n", __func__);
4699c6a44287SMartin K. Petersen 		return -EINVAL;
4700c6a44287SMartin K. Petersen 	}
4701c6a44287SMartin K. Petersen 
4702c6a44287SMartin K. Petersen 	if (scsi_debug_ato > 1) {
4703cbf67842SDouglas Gilbert 		pr_err("%s: ato must be 0 or 1\n", __func__);
4704c6a44287SMartin K. Petersen 		return -EINVAL;
4705c6a44287SMartin K. Petersen 	}
4706c6a44287SMartin K. Petersen 
4707ea61fca5SMartin K. Petersen 	if (scsi_debug_physblk_exp > 15) {
4708cbf67842SDouglas Gilbert 		pr_err("%s: invalid physblk_exp %u\n", __func__,
4709ea61fca5SMartin K. Petersen 		       scsi_debug_physblk_exp);
4710ea61fca5SMartin K. Petersen 		return -EINVAL;
4711ea61fca5SMartin K. Petersen 	}
4712ea61fca5SMartin K. Petersen 
4713ea61fca5SMartin K. Petersen 	if (scsi_debug_lowest_aligned > 0x3fff) {
4714cbf67842SDouglas Gilbert 		pr_err("%s: lowest_aligned too big: %u\n", __func__,
4715ea61fca5SMartin K. Petersen 		       scsi_debug_lowest_aligned);
4716ea61fca5SMartin K. Petersen 		return -EINVAL;
4717ea61fca5SMartin K. Petersen 	}
4718ea61fca5SMartin K. Petersen 
47191da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb < 1)
47201da177e4SLinus Torvalds 		scsi_debug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
47215f2578e5SFUJITA Tomonori 	sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
4722597136abSMartin K. Petersen 	sdebug_store_sectors = sz / scsi_debug_sector_size;
472328898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
47241da177e4SLinus Torvalds 
47251da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
47261da177e4SLinus Torvalds 	sdebug_heads = 8;
47271da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
47281da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb >= 16)
47291da177e4SLinus Torvalds 		sdebug_heads = 32;
47301da177e4SLinus Torvalds 	else if (scsi_debug_dev_size_mb >= 256)
47311da177e4SLinus Torvalds 		sdebug_heads = 64;
47321da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
47331da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
47341da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
47351da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
47361da177e4SLinus Torvalds 		sdebug_heads = 255;
47371da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
47381da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
47391da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
47401da177e4SLinus Torvalds 	}
47411da177e4SLinus Torvalds 
4742cbf67842SDouglas Gilbert 	if (0 == scsi_debug_fake_rw) {
47431da177e4SLinus Torvalds 		fake_storep = vmalloc(sz);
47441da177e4SLinus Torvalds 		if (NULL == fake_storep) {
4745cbf67842SDouglas Gilbert 			pr_err("%s: out of memory, 1\n", __func__);
47461da177e4SLinus Torvalds 			return -ENOMEM;
47471da177e4SLinus Torvalds 		}
47481da177e4SLinus Torvalds 		memset(fake_storep, 0, sz);
47491da177e4SLinus Torvalds 		if (scsi_debug_num_parts > 0)
4750f58b0efbSFUJITA Tomonori 			sdebug_build_parts(fake_storep, sz);
4751cbf67842SDouglas Gilbert 	}
47521da177e4SLinus Torvalds 
47537cb69d03SAkinobu Mita 	if (scsi_debug_dix) {
4754c6a44287SMartin K. Petersen 		int dif_size;
4755c6a44287SMartin K. Petersen 
4756c6a44287SMartin K. Petersen 		dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
4757c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
4758c6a44287SMartin K. Petersen 
4759cbf67842SDouglas Gilbert 		pr_err("%s: dif_storep %u bytes @ %p\n", __func__, dif_size,
4760cbf67842SDouglas Gilbert 			dif_storep);
4761c6a44287SMartin K. Petersen 
4762c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
4763cbf67842SDouglas Gilbert 			pr_err("%s: out of mem. (DIX)\n", __func__);
4764c6a44287SMartin K. Petersen 			ret = -ENOMEM;
4765c6a44287SMartin K. Petersen 			goto free_vm;
4766c6a44287SMartin K. Petersen 		}
4767c6a44287SMartin K. Petersen 
4768c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
4769c6a44287SMartin K. Petersen 	}
4770c6a44287SMartin K. Petersen 
47715b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
47725b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
47736014759cSMartin K. Petersen 		scsi_debug_unmap_max_blocks =
47746014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU);
47756014759cSMartin K. Petersen 
47766014759cSMartin K. Petersen 		scsi_debug_unmap_max_desc =
47776014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_max_desc, 0U, 256U);
47786014759cSMartin K. Petersen 
47796014759cSMartin K. Petersen 		scsi_debug_unmap_granularity =
47806014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU);
47816014759cSMartin K. Petersen 
47826014759cSMartin K. Petersen 		if (scsi_debug_unmap_alignment &&
4783ac17078aSAkinobu Mita 		    scsi_debug_unmap_granularity <=
4784ac17078aSAkinobu Mita 		    scsi_debug_unmap_alignment) {
4785cbf67842SDouglas Gilbert 			pr_err("%s: ERR: unmap_granularity <= unmap_alignment\n",
478644d92694SMartin K. Petersen 			       __func__);
478744d92694SMartin K. Petersen 			return -EINVAL;
478844d92694SMartin K. Petersen 		}
478944d92694SMartin K. Petersen 
4790b90ebc3dSAkinobu Mita 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
4791b90ebc3dSAkinobu Mita 		map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
479244d92694SMartin K. Petersen 
4793cbf67842SDouglas Gilbert 		pr_info("%s: %lu provisioning blocks\n", __func__, map_size);
479444d92694SMartin K. Petersen 
479544d92694SMartin K. Petersen 		if (map_storep == NULL) {
4796cbf67842SDouglas Gilbert 			pr_err("%s: out of mem. (MAP)\n", __func__);
479744d92694SMartin K. Petersen 			ret = -ENOMEM;
479844d92694SMartin K. Petersen 			goto free_vm;
479944d92694SMartin K. Petersen 		}
480044d92694SMartin K. Petersen 
4801b90ebc3dSAkinobu Mita 		bitmap_zero(map_storep, map_size);
480244d92694SMartin K. Petersen 
480344d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
480444d92694SMartin K. Petersen 		if (scsi_debug_num_parts)
480544d92694SMartin K. Petersen 			map_region(0, 2);
480644d92694SMartin K. Petersen 	}
480744d92694SMartin K. Petersen 
48089b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
48099b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
4810cbf67842SDouglas Gilbert 		pr_warn("%s: root_device_register() error\n", __func__);
48119b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
48126ecaff7fSRandy Dunlap 		goto free_vm;
48136ecaff7fSRandy Dunlap 	}
48146ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
48156ecaff7fSRandy Dunlap 	if (ret < 0) {
4816cbf67842SDouglas Gilbert 		pr_warn("%s: bus_register error: %d\n", __func__, ret);
48176ecaff7fSRandy Dunlap 		goto dev_unreg;
48186ecaff7fSRandy Dunlap 	}
48196ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
48206ecaff7fSRandy Dunlap 	if (ret < 0) {
4821cbf67842SDouglas Gilbert 		pr_warn("%s: driver_register error: %d\n", __func__, ret);
48226ecaff7fSRandy Dunlap 		goto bus_unreg;
48236ecaff7fSRandy Dunlap 	}
48241da177e4SLinus Torvalds 
48251da177e4SLinus Torvalds 	host_to_add = scsi_debug_add_host;
48261da177e4SLinus Torvalds         scsi_debug_add_host = 0;
48271da177e4SLinus Torvalds 
48281da177e4SLinus Torvalds         for (k = 0; k < host_to_add; k++) {
48291da177e4SLinus Torvalds                 if (sdebug_add_adapter()) {
4830cbf67842SDouglas Gilbert 			pr_err("%s: sdebug_add_adapter failed k=%d\n",
4831cbf67842SDouglas Gilbert 				__func__, k);
48321da177e4SLinus Torvalds                         break;
48331da177e4SLinus Torvalds                 }
48341da177e4SLinus Torvalds         }
48351da177e4SLinus Torvalds 
48361da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
4837cbf67842SDouglas Gilbert 		pr_info("%s: built %d host(s)\n", __func__,
48381da177e4SLinus Torvalds 			scsi_debug_add_host);
48391da177e4SLinus Torvalds 	}
48401da177e4SLinus Torvalds 	return 0;
48416ecaff7fSRandy Dunlap 
48426ecaff7fSRandy Dunlap bus_unreg:
48436ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
48446ecaff7fSRandy Dunlap dev_unreg:
48459b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
48466ecaff7fSRandy Dunlap free_vm:
484744d92694SMartin K. Petersen 	if (map_storep)
484844d92694SMartin K. Petersen 		vfree(map_storep);
4849c6a44287SMartin K. Petersen 	if (dif_storep)
4850c6a44287SMartin K. Petersen 		vfree(dif_storep);
48516ecaff7fSRandy Dunlap 	vfree(fake_storep);
48526ecaff7fSRandy Dunlap 
48536ecaff7fSRandy Dunlap 	return ret;
48541da177e4SLinus Torvalds }
48551da177e4SLinus Torvalds 
48561da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
48571da177e4SLinus Torvalds {
48581da177e4SLinus Torvalds 	int k = scsi_debug_add_host;
48591da177e4SLinus Torvalds 
48601da177e4SLinus Torvalds 	stop_all_queued();
4861cbf67842SDouglas Gilbert 	free_all_queued();
48621da177e4SLinus Torvalds 	for (; k; k--)
48631da177e4SLinus Torvalds 		sdebug_remove_adapter();
48641da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
48651da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
48669b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
48671da177e4SLinus Torvalds 
4868c6a44287SMartin K. Petersen 	if (dif_storep)
4869c6a44287SMartin K. Petersen 		vfree(dif_storep);
4870c6a44287SMartin K. Petersen 
48711da177e4SLinus Torvalds 	vfree(fake_storep);
48721da177e4SLinus Torvalds }
48731da177e4SLinus Torvalds 
48741da177e4SLinus Torvalds device_initcall(scsi_debug_init);
48751da177e4SLinus Torvalds module_exit(scsi_debug_exit);
48761da177e4SLinus Torvalds 
48771da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev)
48781da177e4SLinus Torvalds {
48791da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
48801da177e4SLinus Torvalds 
48811da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
48821da177e4SLinus Torvalds         kfree(sdbg_host);
48831da177e4SLinus Torvalds }
48841da177e4SLinus Torvalds 
48851da177e4SLinus Torvalds static int sdebug_add_adapter(void)
48861da177e4SLinus Torvalds {
48871da177e4SLinus Torvalds 	int k, devs_per_host;
48881da177e4SLinus Torvalds         int error = 0;
48891da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
48908b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
48911da177e4SLinus Torvalds 
489224669f75SJes Sorensen         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
48931da177e4SLinus Torvalds         if (NULL == sdbg_host) {
48941da177e4SLinus Torvalds                 printk(KERN_ERR "%s: out of memory at line %d\n",
4895cadbd4a5SHarvey Harrison                        __func__, __LINE__);
48961da177e4SLinus Torvalds                 return -ENOMEM;
48971da177e4SLinus Torvalds         }
48981da177e4SLinus Torvalds 
48991da177e4SLinus Torvalds         INIT_LIST_HEAD(&sdbg_host->dev_info_list);
49001da177e4SLinus Torvalds 
49011da177e4SLinus Torvalds 	devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
49021da177e4SLinus Torvalds         for (k = 0; k < devs_per_host; k++) {
49035cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
49045cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
49051da177e4SLinus Torvalds                         printk(KERN_ERR "%s: out of memory at line %d\n",
4906cadbd4a5SHarvey Harrison                                __func__, __LINE__);
49071da177e4SLinus Torvalds                         error = -ENOMEM;
49081da177e4SLinus Torvalds 			goto clean;
49091da177e4SLinus Torvalds                 }
49101da177e4SLinus Torvalds         }
49111da177e4SLinus Torvalds 
49121da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
49131da177e4SLinus Torvalds         list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
49141da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
49151da177e4SLinus Torvalds 
49161da177e4SLinus Torvalds         sdbg_host->dev.bus = &pseudo_lld_bus;
49179b906779SNicholas Bellinger         sdbg_host->dev.parent = pseudo_primary;
49181da177e4SLinus Torvalds         sdbg_host->dev.release = &sdebug_release_adapter;
491971610f55SKay Sievers         dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
49201da177e4SLinus Torvalds 
49211da177e4SLinus Torvalds         error = device_register(&sdbg_host->dev);
49221da177e4SLinus Torvalds 
49231da177e4SLinus Torvalds         if (error)
49241da177e4SLinus Torvalds 		goto clean;
49251da177e4SLinus Torvalds 
49261da177e4SLinus Torvalds 	++scsi_debug_add_host;
49271da177e4SLinus Torvalds         return error;
49281da177e4SLinus Torvalds 
49291da177e4SLinus Torvalds clean:
49308b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
49318b40228fSFUJITA Tomonori 				 dev_list) {
49321da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
49331da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
49341da177e4SLinus Torvalds 	}
49351da177e4SLinus Torvalds 
49361da177e4SLinus Torvalds 	kfree(sdbg_host);
49371da177e4SLinus Torvalds         return error;
49381da177e4SLinus Torvalds }
49391da177e4SLinus Torvalds 
49401da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
49411da177e4SLinus Torvalds {
49421da177e4SLinus Torvalds         struct sdebug_host_info * sdbg_host = NULL;
49431da177e4SLinus Torvalds 
49441da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
49451da177e4SLinus Torvalds         if (!list_empty(&sdebug_host_list)) {
49461da177e4SLinus Torvalds                 sdbg_host = list_entry(sdebug_host_list.prev,
49471da177e4SLinus Torvalds                                        struct sdebug_host_info, host_list);
49481da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
49491da177e4SLinus Torvalds 	}
49501da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
49511da177e4SLinus Torvalds 
49521da177e4SLinus Torvalds 	if (!sdbg_host)
49531da177e4SLinus Torvalds 		return;
49541da177e4SLinus Torvalds 
49551da177e4SLinus Torvalds         device_unregister(&sdbg_host->dev);
49561da177e4SLinus Torvalds         --scsi_debug_add_host;
49571da177e4SLinus Torvalds }
49581da177e4SLinus Torvalds 
4959cbf67842SDouglas Gilbert static int
4960db5ed4dfSChristoph Hellwig sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
4961cbf67842SDouglas Gilbert {
4962cbf67842SDouglas Gilbert 	int num_in_q = 0;
4963cbf67842SDouglas Gilbert 	unsigned long iflags;
4964cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4965cbf67842SDouglas Gilbert 
4966cbf67842SDouglas Gilbert 	spin_lock_irqsave(&queued_arr_lock, iflags);
4967cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
4968cbf67842SDouglas Gilbert 	if (NULL == devip) {
4969cbf67842SDouglas Gilbert 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
4970cbf67842SDouglas Gilbert 		return	-ENODEV;
4971cbf67842SDouglas Gilbert 	}
4972cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
4973cbf67842SDouglas Gilbert 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
4974c40ecc12SChristoph Hellwig 
4975cbf67842SDouglas Gilbert 	if (qdepth < 1)
4976cbf67842SDouglas Gilbert 		qdepth = 1;
4977cbf67842SDouglas Gilbert 	/* allow to exceed max host queued_arr elements for testing */
4978cbf67842SDouglas Gilbert 	if (qdepth > SCSI_DEBUG_CANQUEUE + 10)
4979cbf67842SDouglas Gilbert 		qdepth = SCSI_DEBUG_CANQUEUE + 10;
4980db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
4981cbf67842SDouglas Gilbert 
4982c40ecc12SChristoph Hellwig 	if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) {
4983cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev,
4984c40ecc12SChristoph Hellwig 			    "%s: qdepth=%d, num_in_q=%d\n",
4985c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
4986cbf67842SDouglas Gilbert 	}
4987cbf67842SDouglas Gilbert 	return sdev->queue_depth;
4988cbf67842SDouglas Gilbert }
4989cbf67842SDouglas Gilbert 
4990cbf67842SDouglas Gilbert static int
4991817fd66bSDouglas Gilbert check_inject(struct scsi_cmnd *scp)
4992817fd66bSDouglas Gilbert {
4993817fd66bSDouglas Gilbert 	struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
4994817fd66bSDouglas Gilbert 
4995817fd66bSDouglas Gilbert 	memset(ep, 0, sizeof(struct sdebug_scmd_extra_t));
4996817fd66bSDouglas Gilbert 
4997817fd66bSDouglas Gilbert 	if (atomic_inc_return(&sdebug_cmnd_count) >=
4998817fd66bSDouglas Gilbert 	    abs(scsi_debug_every_nth)) {
4999817fd66bSDouglas Gilbert 		atomic_set(&sdebug_cmnd_count, 0);
5000817fd66bSDouglas Gilbert 		if (scsi_debug_every_nth < -1)
5001817fd66bSDouglas Gilbert 			scsi_debug_every_nth = -1;
5002817fd66bSDouglas Gilbert 		if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
5003817fd66bSDouglas Gilbert 			return 1; /* ignore command causing timeout */
5004817fd66bSDouglas Gilbert 		else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts &&
5005817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
5006817fd66bSDouglas Gilbert 			return 1; /* time out reads and writes */
5007817fd66bSDouglas Gilbert 		if (sdebug_any_injecting_opt) {
5008817fd66bSDouglas Gilbert 			int opts = scsi_debug_opts;
5009817fd66bSDouglas Gilbert 
5010817fd66bSDouglas Gilbert 			if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts)
5011817fd66bSDouglas Gilbert 				ep->inj_recovered = true;
5012817fd66bSDouglas Gilbert 			else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts)
5013817fd66bSDouglas Gilbert 				ep->inj_transport = true;
5014817fd66bSDouglas Gilbert 			else if (SCSI_DEBUG_OPT_DIF_ERR & opts)
5015817fd66bSDouglas Gilbert 				ep->inj_dif = true;
5016817fd66bSDouglas Gilbert 			else if (SCSI_DEBUG_OPT_DIX_ERR & opts)
5017817fd66bSDouglas Gilbert 				ep->inj_dix = true;
5018817fd66bSDouglas Gilbert 			else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts)
5019817fd66bSDouglas Gilbert 				ep->inj_short = true;
5020817fd66bSDouglas Gilbert 		}
5021817fd66bSDouglas Gilbert 	}
5022817fd66bSDouglas Gilbert 	return 0;
5023817fd66bSDouglas Gilbert }
5024817fd66bSDouglas Gilbert 
5025c2248fc9SDouglas Gilbert static int
5026c2248fc9SDouglas Gilbert scsi_debug_queuecommand(struct scsi_cmnd *scp)
5027c2248fc9SDouglas Gilbert {
5028c2248fc9SDouglas Gilbert 	u8 sdeb_i;
5029c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
5030c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
5031c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
5032c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
5033c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
5034c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5035c2248fc9SDouglas Gilbert 	int k, na;
5036c2248fc9SDouglas Gilbert 	int errsts = 0;
5037c2248fc9SDouglas Gilbert 	int errsts_no_connect = DID_NO_CONNECT << 16;
5038c2248fc9SDouglas Gilbert 	u32 flags;
5039c2248fc9SDouglas Gilbert 	u16 sa;
5040c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
5041c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
5042c2248fc9SDouglas Gilbert 	bool debug = !!(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts);
5043c2248fc9SDouglas Gilbert 
5044c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
5045c2248fc9SDouglas Gilbert 	if (debug && !(SCSI_DEBUG_OPT_NO_CDB_NOISE & scsi_debug_opts)) {
5046c2248fc9SDouglas Gilbert 		char b[120];
5047c2248fc9SDouglas Gilbert 		int n, len, sb;
5048c2248fc9SDouglas Gilbert 
5049c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
5050c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
5051c2248fc9SDouglas Gilbert 		if (len > 32)
5052c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
5053c2248fc9SDouglas Gilbert 		else {
5054c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
5055c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
5056c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
5057c2248fc9SDouglas Gilbert 		}
5058c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, b);
5059c2248fc9SDouglas Gilbert 	}
5060c2248fc9SDouglas Gilbert 	has_wlun_rl = (sdp->lun == SAM2_WLUN_REPORT_LUNS);
5061c2248fc9SDouglas Gilbert 	if ((sdp->lun >= scsi_debug_max_luns) && !has_wlun_rl)
5062c2248fc9SDouglas Gilbert 		return schedule_resp(scp, NULL, errsts_no_connect, 0);
5063c2248fc9SDouglas Gilbert 
5064c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
5065c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
5066c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
5067c2248fc9SDouglas Gilbert 	if (!devip) {
5068c2248fc9SDouglas Gilbert 		devip = devInfoReg(sdp);
5069c2248fc9SDouglas Gilbert 		if (NULL == devip)
5070c2248fc9SDouglas Gilbert 			return schedule_resp(scp, NULL, errsts_no_connect, 0);
5071c2248fc9SDouglas Gilbert 	}
5072c2248fc9SDouglas Gilbert 	na = oip->num_attached;
5073c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
5074c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
5075c2248fc9SDouglas Gilbert 		r_oip = oip;
5076c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
5077c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
5078c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
5079c2248fc9SDouglas Gilbert 			else
5080c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
5081c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5082c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
5083c2248fc9SDouglas Gilbert 					break;
5084c2248fc9SDouglas Gilbert 			}
5085c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
5086c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5087c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
5088c2248fc9SDouglas Gilbert 					break;
5089c2248fc9SDouglas Gilbert 			}
5090c2248fc9SDouglas Gilbert 		}
5091c2248fc9SDouglas Gilbert 		if (k > na) {
5092c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
5093c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5094c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
5095c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5096c2248fc9SDouglas Gilbert 			else
5097c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
5098c2248fc9SDouglas Gilbert 			goto check_cond;
5099c2248fc9SDouglas Gilbert 		}
5100c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
5101c2248fc9SDouglas Gilbert 	flags = oip->flags;
5102c2248fc9SDouglas Gilbert 	if (F_INV_OP & flags) {
5103c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5104c2248fc9SDouglas Gilbert 		goto check_cond;
5105c2248fc9SDouglas Gilbert 	}
5106c2248fc9SDouglas Gilbert 	if (has_wlun_rl && !(F_RL_WLUN_OK & flags)) {
5107c2248fc9SDouglas Gilbert 		if (debug)
5108c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "scsi_debug: Opcode: "
5109c2248fc9SDouglas Gilbert 				    "0x%x not supported for wlun\n", opcode);
5110c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5111c2248fc9SDouglas Gilbert 		goto check_cond;
5112c2248fc9SDouglas Gilbert 	}
5113c2248fc9SDouglas Gilbert 	if (scsi_debug_strict) {	/* check cdb against mask */
5114c2248fc9SDouglas Gilbert 		u8 rem;
5115c2248fc9SDouglas Gilbert 		int j;
5116c2248fc9SDouglas Gilbert 
5117c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5118c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
5119c2248fc9SDouglas Gilbert 			if (rem) {
5120c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
5121c2248fc9SDouglas Gilbert 					if (0x80 & rem)
5122c2248fc9SDouglas Gilbert 						break;
5123c2248fc9SDouglas Gilbert 				}
5124c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5125c2248fc9SDouglas Gilbert 				goto check_cond;
5126c2248fc9SDouglas Gilbert 			}
5127c2248fc9SDouglas Gilbert 		}
5128c2248fc9SDouglas Gilbert 	}
5129c2248fc9SDouglas Gilbert 	if (!(F_SKIP_UA & flags) &&
5130c2248fc9SDouglas Gilbert 	    SDEBUG_NUM_UAS != find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS)) {
5131c2248fc9SDouglas Gilbert 		errsts = check_readiness(scp, UAS_ONLY, devip);
5132c2248fc9SDouglas Gilbert 		if (errsts)
5133c2248fc9SDouglas Gilbert 			goto check_cond;
5134c2248fc9SDouglas Gilbert 	}
5135c2248fc9SDouglas Gilbert 	if ((F_M_ACCESS & flags) && devip->stopped) {
5136c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
5137c2248fc9SDouglas Gilbert 		if (debug)
5138c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5139c2248fc9SDouglas Gilbert 				    "%s\n", my_name, "initializing command "
5140c2248fc9SDouglas Gilbert 				    "required");
5141c2248fc9SDouglas Gilbert 		errsts = check_condition_result;
5142c2248fc9SDouglas Gilbert 		goto fini;
5143c2248fc9SDouglas Gilbert 	}
5144c2248fc9SDouglas Gilbert 	if (scsi_debug_fake_rw && (F_FAKE_RW & flags))
5145c2248fc9SDouglas Gilbert 		goto fini;
5146c2248fc9SDouglas Gilbert 	if (scsi_debug_every_nth) {
5147c2248fc9SDouglas Gilbert 		if (check_inject(scp))
5148c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
5149c2248fc9SDouglas Gilbert 	}
5150c2248fc9SDouglas Gilbert 	if (oip->pfp)	/* if this command has a resp_* function, call it */
5151c2248fc9SDouglas Gilbert 		errsts = oip->pfp(scp, devip);
5152c2248fc9SDouglas Gilbert 	else if (r_pfp)	/* if leaf function ptr NULL, try the root's */
5153c2248fc9SDouglas Gilbert 		errsts = r_pfp(scp, devip);
5154c2248fc9SDouglas Gilbert 
5155c2248fc9SDouglas Gilbert fini:
5156c2248fc9SDouglas Gilbert 	return schedule_resp(scp, devip, errsts,
5157c2248fc9SDouglas Gilbert 			     ((F_DELAY_OVERR & flags) ? 0 : scsi_debug_delay));
5158c2248fc9SDouglas Gilbert check_cond:
5159c2248fc9SDouglas Gilbert 	return schedule_resp(scp, devip, check_condition_result, 0);
5160c2248fc9SDouglas Gilbert }
5161c2248fc9SDouglas Gilbert 
516238d5c833SDouglas Gilbert static int
516338d5c833SDouglas Gilbert sdebug_queuecommand_lock_or_not(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
516438d5c833SDouglas Gilbert {
516538d5c833SDouglas Gilbert 	if (scsi_debug_host_lock) {
516638d5c833SDouglas Gilbert 		unsigned long iflags;
516738d5c833SDouglas Gilbert 		int rc;
516838d5c833SDouglas Gilbert 
516938d5c833SDouglas Gilbert 		spin_lock_irqsave(shost->host_lock, iflags);
517038d5c833SDouglas Gilbert 		rc = scsi_debug_queuecommand(cmd);
517138d5c833SDouglas Gilbert 		spin_unlock_irqrestore(shost->host_lock, iflags);
517238d5c833SDouglas Gilbert 		return rc;
517338d5c833SDouglas Gilbert 	} else
517438d5c833SDouglas Gilbert 		return scsi_debug_queuecommand(cmd);
517538d5c833SDouglas Gilbert }
517638d5c833SDouglas Gilbert 
51779e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
5178c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
5179c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
51809e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
51819e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
51829e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
51839e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
51849e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
51859e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
51869e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
5187cbf67842SDouglas Gilbert 	.queuecommand =		sdebug_queuecommand_lock_or_not,
5188cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
51899e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
51909e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
5191cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
5192cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
51939e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
51949e603ca0SFUJITA Tomonori 	.can_queue =		SCSI_DEBUG_CANQUEUE,
51959e603ca0SFUJITA Tomonori 	.this_id =		7,
51966bb5e6e7SAkinobu Mita 	.sg_tablesize =		SCSI_MAX_SG_CHAIN_SEGMENTS,
5197cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
51986bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
51999e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
52009e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
5201c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
5202817fd66bSDouglas Gilbert 	.cmd_size =		sizeof(struct sdebug_scmd_extra_t),
52039e603ca0SFUJITA Tomonori };
52049e603ca0SFUJITA Tomonori 
52051da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev)
52061da177e4SLinus Torvalds {
52071da177e4SLinus Torvalds 	int error = 0;
5208817fd66bSDouglas Gilbert 	int opts;
52091da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
52101da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
5211c6a44287SMartin K. Petersen 	int host_prot;
52121da177e4SLinus Torvalds 
52131da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
52141da177e4SLinus Torvalds 
521578d4e5a0SDouglas Gilbert 	sdebug_driver_template.can_queue = scsi_debug_max_queue;
52160759c666SAkinobu Mita 	if (scsi_debug_clustering)
52170759c666SAkinobu Mita 		sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
52181da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
52191da177e4SLinus Torvalds 	if (NULL == hpnt) {
522017c9ff52SFinn Thain 		pr_err("%s: scsi_host_alloc failed\n", __func__);
52211da177e4SLinus Torvalds 		error = -ENODEV;
52221da177e4SLinus Torvalds 		return error;
52231da177e4SLinus Torvalds 	}
52241da177e4SLinus Torvalds 
52251da177e4SLinus Torvalds         sdbg_host->shost = hpnt;
52261da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
52271da177e4SLinus Torvalds 	if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
52281da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts + 1;
52291da177e4SLinus Torvalds 	else
52301da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts;
5231c65b1445SDouglas Gilbert 	hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;	/* = scsi_debug_max_luns; */
52321da177e4SLinus Torvalds 
5233c6a44287SMartin K. Petersen 	host_prot = 0;
5234c6a44287SMartin K. Petersen 
5235c6a44287SMartin K. Petersen 	switch (scsi_debug_dif) {
5236c6a44287SMartin K. Petersen 
5237c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
5238c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE1_PROTECTION;
5239c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
5240c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE1_PROTECTION;
5241c6a44287SMartin K. Petersen 		break;
5242c6a44287SMartin K. Petersen 
5243c6a44287SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
5244c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE2_PROTECTION;
5245c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
5246c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE2_PROTECTION;
5247c6a44287SMartin K. Petersen 		break;
5248c6a44287SMartin K. Petersen 
5249c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
5250c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE3_PROTECTION;
5251c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
5252c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE3_PROTECTION;
5253c6a44287SMartin K. Petersen 		break;
5254c6a44287SMartin K. Petersen 
5255c6a44287SMartin K. Petersen 	default:
5256c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
5257c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE0_PROTECTION;
5258c6a44287SMartin K. Petersen 		break;
5259c6a44287SMartin K. Petersen 	}
5260c6a44287SMartin K. Petersen 
5261c6a44287SMartin K. Petersen 	scsi_host_set_prot(hpnt, host_prot);
5262c6a44287SMartin K. Petersen 
5263c6a44287SMartin K. Petersen 	printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
5264c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5265c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5266c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5267c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5268c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5269c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5270c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
5271c6a44287SMartin K. Petersen 
5272c6a44287SMartin K. Petersen 	if (scsi_debug_guard == 1)
5273c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5274c6a44287SMartin K. Petersen 	else
5275c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5276c6a44287SMartin K. Petersen 
5277817fd66bSDouglas Gilbert 	opts = scsi_debug_opts;
5278817fd66bSDouglas Gilbert 	if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts)
5279817fd66bSDouglas Gilbert 		sdebug_any_injecting_opt = true;
5280817fd66bSDouglas Gilbert 	else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts)
5281817fd66bSDouglas Gilbert 		sdebug_any_injecting_opt = true;
5282817fd66bSDouglas Gilbert 	else if (SCSI_DEBUG_OPT_DIF_ERR & opts)
5283817fd66bSDouglas Gilbert 		sdebug_any_injecting_opt = true;
5284817fd66bSDouglas Gilbert 	else if (SCSI_DEBUG_OPT_DIX_ERR & opts)
5285817fd66bSDouglas Gilbert 		sdebug_any_injecting_opt = true;
5286817fd66bSDouglas Gilbert 	else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts)
5287817fd66bSDouglas Gilbert 		sdebug_any_injecting_opt = true;
5288817fd66bSDouglas Gilbert 
52891da177e4SLinus Torvalds         error = scsi_add_host(hpnt, &sdbg_host->dev);
52901da177e4SLinus Torvalds         if (error) {
5291cadbd4a5SHarvey Harrison                 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
52921da177e4SLinus Torvalds                 error = -ENODEV;
52931da177e4SLinus Torvalds 		scsi_host_put(hpnt);
52941da177e4SLinus Torvalds         } else
52951da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
52961da177e4SLinus Torvalds 
52971da177e4SLinus Torvalds 	return error;
52981da177e4SLinus Torvalds }
52991da177e4SLinus Torvalds 
53001da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev)
53011da177e4SLinus Torvalds {
53021da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
53038b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
53041da177e4SLinus Torvalds 
53051da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
53061da177e4SLinus Torvalds 
53071da177e4SLinus Torvalds 	if (!sdbg_host) {
53081da177e4SLinus Torvalds 		printk(KERN_ERR "%s: Unable to locate host info\n",
5309cadbd4a5SHarvey Harrison 		       __func__);
53101da177e4SLinus Torvalds 		return -ENODEV;
53111da177e4SLinus Torvalds 	}
53121da177e4SLinus Torvalds 
53131da177e4SLinus Torvalds         scsi_remove_host(sdbg_host->shost);
53141da177e4SLinus Torvalds 
53158b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
53168b40228fSFUJITA Tomonori 				 dev_list) {
53171da177e4SLinus Torvalds                 list_del(&sdbg_devinfo->dev_list);
53181da177e4SLinus Torvalds                 kfree(sdbg_devinfo);
53191da177e4SLinus Torvalds         }
53201da177e4SLinus Torvalds 
53211da177e4SLinus Torvalds         scsi_host_put(sdbg_host->shost);
53221da177e4SLinus Torvalds         return 0;
53231da177e4SLinus Torvalds }
53241da177e4SLinus Torvalds 
53258dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
53268dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
53271da177e4SLinus Torvalds {
53288dea0d02SFUJITA Tomonori 	return 1;
53298dea0d02SFUJITA Tomonori }
53301da177e4SLinus Torvalds 
53318dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
53328dea0d02SFUJITA Tomonori 	.name = "pseudo",
53338dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
53348dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
53358dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
533682069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
53378dea0d02SFUJITA Tomonori };
5338