xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision c40ecc12)
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 
66cbf67842SDouglas Gilbert #define SCSI_DEBUG_VERSION "1.84"
67cbf67842SDouglas Gilbert static const char *scsi_debug_version_date = "20140706";
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
74c5af0db9SAkinobu Mita #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
781da177e4SLinus Torvalds #define ADDR_OUT_OF_RANGE 0x21
79395cef03SMartin K. Petersen #define INVALID_COMMAND_OPCODE 0x20
801da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
81c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
82cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
83cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
84cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
85cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
86cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
871da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
886f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
89c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
90c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
911da177e4SLinus Torvalds 
926f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
936f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
946f3cbf55SDouglas Gilbert 
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds /* Default values for driver parameters */
971da177e4SLinus Torvalds #define DEF_NUM_HOST   1
981da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
991da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1001da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1011da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1021da177e4SLinus Torvalds  */
1035b94e232SMartin K. Petersen #define DEF_ATO 1
104cbf67842SDouglas Gilbert #define DEF_DELAY   1		/* if > 0 unit is a jiffy */
1051da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1065b94e232SMartin K. Petersen #define DEF_DIF 0
1075b94e232SMartin K. Petersen #define DEF_DIX 0
1085b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1091da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1105b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1115b94e232SMartin K. Petersen #define DEF_GUARD 0
112cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1135b94e232SMartin K. Petersen #define DEF_LBPU 0
1145b94e232SMartin K. Petersen #define DEF_LBPWS 0
1155b94e232SMartin K. Petersen #define DEF_LBPWS10 0
116be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1175b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
118cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1195b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1201da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1211da177e4SLinus Torvalds #define DEF_OPTS   0
122e308b3d1SMartin K. Petersen #define DEF_OPT_BLKS 64
1235b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
1245b94e232SMartin K. Petersen #define DEF_PTYPE   0
125d986788bSMartin Pitt #define DEF_REMOVABLE false
126e46b0344SDouglas Gilbert #define DEF_SCSI_LEVEL   6    /* INQUIRY, byte2 [6->SPC-4] */
1275b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
128cbf67842SDouglas Gilbert #define DEF_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
1295b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1305b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1316014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1326014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1335b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1345b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1355b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
136cbf67842SDouglas Gilbert #define DELAY_OVERRIDDEN -9999
1371da177e4SLinus Torvalds 
1381da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */
1391da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE   1
1401da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR   2
1411da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT   4
1421da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR   8
1436f3cbf55SDouglas Gilbert #define SCSI_DEBUG_OPT_TRANSPORT_ERR   16
144c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIF_ERR   32
145c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIX_ERR   64
14618a4d0a2SMartin K. Petersen #define SCSI_DEBUG_OPT_MAC_TIMEOUT  128
147cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_SHORT_TRANSFER	0x100
148cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_Q_NOISE	0x200
149cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_ALL_TSF	0x400
150cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_RARE_TSF	0x800
151cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_N_WCE	0x1000
152cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_RESET_NOISE 0x2000
153cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_NO_CDB_NOISE 0x4000
154cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_ALL_NOISE (0x1 | 0x200 | 0x2000)
1551da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
1561da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1571da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1581da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1596f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1606f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1611da177e4SLinus Torvalds  *
1621da177e4SLinus Torvalds  * When "every_nth" < 0 then after "- every_nth" commands:
1631da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1641da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1651da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1666f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1676f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1681da177e4SLinus Torvalds  * This will continue until some other action occurs (e.g. the user
1691da177e4SLinus Torvalds  * writing a new value (other than -1 or 1) to every_nth via sysfs).
1701da177e4SLinus Torvalds  */
1711da177e4SLinus Torvalds 
172cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs)are returned in
173cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
174cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
175cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
176cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
177cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1
178cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2
179cbf67842SDouglas Gilbert #define SDEBUG_NUM_UAS 3
180cbf67842SDouglas Gilbert 
181cbf67842SDouglas Gilbert /* for check_readiness() */
182cbf67842SDouglas Gilbert #define UAS_ONLY 1
183cbf67842SDouglas Gilbert #define UAS_TUR 0
184cbf67842SDouglas Gilbert 
1851da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
1861da177e4SLinus Torvalds  * sector on read commands: */
1871da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
18832f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
1911da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
1921da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
193c65b1445SDouglas Gilbert #define SAM2_WLUN_REPORT_LUNS 0xc101
1941da177e4SLinus Torvalds 
195cbf67842SDouglas Gilbert /* SCSI_DEBUG_CANQUEUE is the maximum number of commands that can be queued
196cbf67842SDouglas Gilbert  * (for response) at one time. Can be reduced by max_queue option. Command
197cbf67842SDouglas Gilbert  * responses are not queued when delay=0 and ndelay=0. The per-device
198cbf67842SDouglas Gilbert  * DEF_CMD_PER_LUN can be changed via sysfs:
199cbf67842SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth but cannot exceed
200cbf67842SDouglas Gilbert  * SCSI_DEBUG_CANQUEUE. */
201cbf67842SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE_WORDS  9	/* a WORD is bits in a long */
202cbf67842SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE  (SCSI_DEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
203cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN  255
204cbf67842SDouglas Gilbert 
205cbf67842SDouglas Gilbert #if DEF_CMD_PER_LUN > SCSI_DEBUG_CANQUEUE
206cbf67842SDouglas Gilbert #warning "Expect DEF_CMD_PER_LUN <= SCSI_DEBUG_CANQUEUE"
207cbf67842SDouglas Gilbert #endif
20878d4e5a0SDouglas Gilbert 
2091da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST;
2105b94e232SMartin K. Petersen static int scsi_debug_ato = DEF_ATO;
2111da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY;
2121da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
2135b94e232SMartin K. Petersen static int scsi_debug_dif = DEF_DIF;
2145b94e232SMartin K. Petersen static int scsi_debug_dix = DEF_DIX;
2155b94e232SMartin K. Petersen static int scsi_debug_dsense = DEF_D_SENSE;
2161da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH;
2175b94e232SMartin K. Petersen static int scsi_debug_fake_rw = DEF_FAKE_RW;
21868aee7baSAkinobu Mita static unsigned int scsi_debug_guard = DEF_GUARD;
2195b94e232SMartin K. Petersen static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
2201da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS;
22178d4e5a0SDouglas Gilbert static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE;
222cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
223cbf67842SDouglas Gilbert static int scsi_debug_ndelay = DEF_NDELAY;
224c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
2255b94e232SMartin K. Petersen static int scsi_debug_no_uld = 0;
2265b94e232SMartin K. Petersen static int scsi_debug_num_parts = DEF_NUM_PARTS;
2275b94e232SMartin K. Petersen static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
228e308b3d1SMartin K. Petersen static int scsi_debug_opt_blks = DEF_OPT_BLKS;
2295b94e232SMartin K. Petersen static int scsi_debug_opts = DEF_OPTS;
2305b94e232SMartin K. Petersen static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
2315b94e232SMartin K. Petersen static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
2325b94e232SMartin K. Petersen static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
2335b94e232SMartin K. Petersen static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
2345b94e232SMartin K. Petersen static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
2355b94e232SMartin K. Petersen static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
2365b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpu = DEF_LBPU;
2375b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws = DEF_LBPWS;
2385b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10;
239be1dd78dSEric Sandeen static unsigned int scsi_debug_lbprz = DEF_LBPRZ;
2406014759cSMartin K. Petersen static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
2415b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
2425b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
2435b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
2445b94e232SMartin K. Petersen static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH;
245d986788bSMartin Pitt static bool scsi_debug_removable = DEF_REMOVABLE;
2460759c666SAkinobu Mita static bool scsi_debug_clustering;
247cbf67842SDouglas Gilbert static bool scsi_debug_host_lock = DEF_HOST_LOCK;
2481da177e4SLinus Torvalds 
249cbf67842SDouglas Gilbert static atomic_t sdebug_cmnd_count;
250cbf67842SDouglas Gilbert static atomic_t sdebug_completions;
251cbf67842SDouglas Gilbert static atomic_t sdebug_a_tsf;		/* counter of 'almost' TSFs */
2521da177e4SLinus Torvalds 
2531da177e4SLinus Torvalds #define DEV_READONLY(TGT)      (0)
2541da177e4SLinus Torvalds 
255c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
2561da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
2591da177e4SLinus Torvalds    may still need them */
2601da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
2611da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
2621da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
2631da177e4SLinus Torvalds 
2641da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4
2651da177e4SLinus Torvalds 
266395cef03SMartin K. Petersen #define SCSI_DEBUG_MAX_CMD_LEN 32
2679e603ca0SFUJITA Tomonori 
2685b94e232SMartin K. Petersen static unsigned int scsi_debug_lbp(void)
2695b94e232SMartin K. Petersen {
270cbf67842SDouglas Gilbert 	return ((0 == scsi_debug_fake_rw) &&
271cbf67842SDouglas Gilbert 		(scsi_debug_lbpu | scsi_debug_lbpws | scsi_debug_lbpws10));
2725b94e232SMartin K. Petersen }
2735b94e232SMartin K. Petersen 
2741da177e4SLinus Torvalds struct sdebug_dev_info {
2751da177e4SLinus Torvalds 	struct list_head dev_list;
2761da177e4SLinus Torvalds 	unsigned int channel;
2771da177e4SLinus Torvalds 	unsigned int target;
2789cb78c16SHannes Reinecke 	u64 lun;
2791da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
2809cb78c16SHannes Reinecke 	u64 wlun;
281cbf67842SDouglas Gilbert 	unsigned long uas_bm[1];
282cbf67842SDouglas Gilbert 	atomic_t num_in_q;
283c65b1445SDouglas Gilbert 	char stopped;
2841da177e4SLinus Torvalds 	char used;
2851da177e4SLinus Torvalds };
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds struct sdebug_host_info {
2881da177e4SLinus Torvalds 	struct list_head host_list;
2891da177e4SLinus Torvalds 	struct Scsi_Host *shost;
2901da177e4SLinus Torvalds 	struct device dev;
2911da177e4SLinus Torvalds 	struct list_head dev_info_list;
2921da177e4SLinus Torvalds };
2931da177e4SLinus Torvalds 
2941da177e4SLinus Torvalds #define to_sdebug_host(d)	\
2951da177e4SLinus Torvalds 	container_of(d, struct sdebug_host_info, dev)
2961da177e4SLinus Torvalds 
2971da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
2981da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
2991da177e4SLinus Torvalds 
300cbf67842SDouglas Gilbert 
301cbf67842SDouglas Gilbert struct sdebug_hrtimer {		/* ... is derived from hrtimer */
302cbf67842SDouglas Gilbert 	struct hrtimer hrt;	/* must be first element */
303cbf67842SDouglas Gilbert 	int qa_indx;
304cbf67842SDouglas Gilbert };
3051da177e4SLinus Torvalds 
3061da177e4SLinus Torvalds struct sdebug_queued_cmd {
307cbf67842SDouglas Gilbert 	/* in_use flagged by a bit in queued_in_use_bm[] */
308cbf67842SDouglas Gilbert 	struct timer_list *cmnd_timerp;
309cbf67842SDouglas Gilbert 	struct tasklet_struct *tletp;
310cbf67842SDouglas Gilbert 	struct sdebug_hrtimer *sd_hrtp;
3111da177e4SLinus Torvalds 	struct scsi_cmnd * a_cmnd;
3121da177e4SLinus Torvalds };
3131da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
314cbf67842SDouglas Gilbert static unsigned long queued_in_use_bm[SCSI_DEBUG_CANQUEUE_WORDS];
315cbf67842SDouglas Gilbert 
3161da177e4SLinus Torvalds 
3171da177e4SLinus Torvalds static unsigned char * fake_storep;	/* ramdisk storage */
318e18d8beaSAkinobu Mita static struct sd_dif_tuple *dif_storep;	/* protection info */
31944d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
3201da177e4SLinus Torvalds 
32144d92694SMartin K. Petersen static unsigned long map_size;
322cbf67842SDouglas Gilbert static int num_aborts;
323cbf67842SDouglas Gilbert static int num_dev_resets;
324cbf67842SDouglas Gilbert static int num_target_resets;
325cbf67842SDouglas Gilbert static int num_bus_resets;
326cbf67842SDouglas Gilbert static int num_host_resets;
327c6a44287SMartin K. Petersen static int dix_writes;
328c6a44287SMartin K. Petersen static int dix_reads;
329c6a44287SMartin K. Petersen static int dif_errors;
3301da177e4SLinus Torvalds 
3311da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock);
3321da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
3331da177e4SLinus Torvalds 
334cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
335cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
3361da177e4SLinus Torvalds 
3371da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
3381da177e4SLinus Torvalds 
3391da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
3401da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
3411da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
3421da177e4SLinus Torvalds };
3431da177e4SLinus Torvalds 
3441da177e4SLinus Torvalds static const int check_condition_result =
3451da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
3461da177e4SLinus Torvalds 
347c6a44287SMartin K. Petersen static const int illegal_condition_result =
348c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
349c6a44287SMartin K. Petersen 
350cbf67842SDouglas Gilbert static const int device_qfull_result =
351cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
352cbf67842SDouglas Gilbert 
353cbf67842SDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
354cbf67842SDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
355cbf67842SDouglas Gilbert 				     0, 0, 0, 0};
356c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
357c65b1445SDouglas Gilbert 				    0, 0, 0x2, 0x4b};
358c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
359c65b1445SDouglas Gilbert 			           0, 0, 0x0, 0x0};
360c65b1445SDouglas Gilbert 
36114faa944SAkinobu Mita static void *fake_store(unsigned long long lba)
36214faa944SAkinobu Mita {
36314faa944SAkinobu Mita 	lba = do_div(lba, sdebug_store_sectors);
36414faa944SAkinobu Mita 
36514faa944SAkinobu Mita 	return fake_storep + lba * scsi_debug_sector_size;
36614faa944SAkinobu Mita }
36714faa944SAkinobu Mita 
36814faa944SAkinobu Mita static struct sd_dif_tuple *dif_store(sector_t sector)
36914faa944SAkinobu Mita {
37014faa944SAkinobu Mita 	sector = do_div(sector, sdebug_store_sectors);
37114faa944SAkinobu Mita 
37214faa944SAkinobu Mita 	return dif_storep + sector;
37314faa944SAkinobu Mita }
37414faa944SAkinobu Mita 
3751da177e4SLinus Torvalds static int sdebug_add_adapter(void);
3761da177e4SLinus Torvalds static void sdebug_remove_adapter(void);
3771da177e4SLinus Torvalds 
3788dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
3798dea0d02SFUJITA Tomonori {
3808dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
3818dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
3828dea0d02SFUJITA Tomonori 
3838dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
3848dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3858dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
3868dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
3878dea0d02SFUJITA Tomonori 		    (scsi_debug_num_tgts > hpnt->this_id))
3888dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts + 1;
3898dea0d02SFUJITA Tomonori 		else
3908dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts;
3918dea0d02SFUJITA Tomonori 		/* scsi_debug_max_luns; */
3928dea0d02SFUJITA Tomonori 		hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
3938dea0d02SFUJITA Tomonori 	}
3948dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
3958dea0d02SFUJITA Tomonori }
3968dea0d02SFUJITA Tomonori 
397cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
3988dea0d02SFUJITA Tomonori {
3998dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
4008dea0d02SFUJITA Tomonori 
401cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
402cbf67842SDouglas Gilbert 	if (!sbuff) {
403cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
404cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
405cbf67842SDouglas Gilbert 		return;
406cbf67842SDouglas Gilbert 	}
407cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
4088dea0d02SFUJITA Tomonori 
4098dea0d02SFUJITA Tomonori 	scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
4108dea0d02SFUJITA Tomonori 
4118dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
412cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
413cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
414cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
4158dea0d02SFUJITA Tomonori }
4161da177e4SLinus Torvalds 
4173de9f944SFUJITA Tomonori static void get_data_transfer_info(unsigned char *cmd,
418395cef03SMartin K. Petersen 				   unsigned long long *lba, unsigned int *num,
419395cef03SMartin K. Petersen 				   u32 *ei_lba)
4203de9f944SFUJITA Tomonori {
421395cef03SMartin K. Petersen 	*ei_lba = 0;
422395cef03SMartin K. Petersen 
4233de9f944SFUJITA Tomonori 	switch (*cmd) {
424395cef03SMartin K. Petersen 	case VARIABLE_LENGTH_CMD:
425395cef03SMartin K. Petersen 		*lba = (u64)cmd[19] | (u64)cmd[18] << 8 |
426395cef03SMartin K. Petersen 			(u64)cmd[17] << 16 | (u64)cmd[16] << 24 |
427395cef03SMartin K. Petersen 			(u64)cmd[15] << 32 | (u64)cmd[14] << 40 |
428395cef03SMartin K. Petersen 			(u64)cmd[13] << 48 | (u64)cmd[12] << 56;
429395cef03SMartin K. Petersen 
430395cef03SMartin K. Petersen 		*ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 |
431395cef03SMartin K. Petersen 			(u32)cmd[21] << 16 | (u32)cmd[20] << 24;
432395cef03SMartin K. Petersen 
433395cef03SMartin K. Petersen 		*num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 |
434395cef03SMartin K. Petersen 			(u32)cmd[28] << 24;
435395cef03SMartin K. Petersen 		break;
436395cef03SMartin K. Petersen 
43744d92694SMartin K. Petersen 	case WRITE_SAME_16:
4383de9f944SFUJITA Tomonori 	case WRITE_16:
4393de9f944SFUJITA Tomonori 	case READ_16:
440d5cdc989SFUJITA Tomonori 		*lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
441d5cdc989SFUJITA Tomonori 			(u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
442d5cdc989SFUJITA Tomonori 			(u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
443d5cdc989SFUJITA Tomonori 			(u64)cmd[3] << 48 | (u64)cmd[2] << 56;
444d5cdc989SFUJITA Tomonori 
445d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
446d5cdc989SFUJITA Tomonori 			(u32)cmd[10] << 24;
4473de9f944SFUJITA Tomonori 		break;
4483de9f944SFUJITA Tomonori 	case WRITE_12:
4493de9f944SFUJITA Tomonori 	case READ_12:
450d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
451d5cdc989SFUJITA Tomonori 			(u32)cmd[2] << 24;
452d5cdc989SFUJITA Tomonori 
453d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
454d5cdc989SFUJITA Tomonori 			(u32)cmd[6] << 24;
4553de9f944SFUJITA Tomonori 		break;
45644d92694SMartin K. Petersen 	case WRITE_SAME:
4573de9f944SFUJITA Tomonori 	case WRITE_10:
4583de9f944SFUJITA Tomonori 	case READ_10:
459c639d14eSFUJITA Tomonori 	case XDWRITEREAD_10:
460d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[5] | (u32)cmd[4] << 8 |	(u32)cmd[3] << 16 |
461d5cdc989SFUJITA Tomonori 			(u32)cmd[2] << 24;
462d5cdc989SFUJITA Tomonori 
463d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[8] | (u32)cmd[7] << 8;
4643de9f944SFUJITA Tomonori 		break;
4653de9f944SFUJITA Tomonori 	case WRITE_6:
4663de9f944SFUJITA Tomonori 	case READ_6:
467d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
468d5cdc989SFUJITA Tomonori 			(u32)(cmd[1] & 0x1f) << 16;
4693de9f944SFUJITA Tomonori 		*num = (0 == cmd[4]) ? 256 : cmd[4];
4703de9f944SFUJITA Tomonori 		break;
4713de9f944SFUJITA Tomonori 	default:
4723de9f944SFUJITA Tomonori 		break;
4733de9f944SFUJITA Tomonori 	}
4743de9f944SFUJITA Tomonori }
4751da177e4SLinus Torvalds 
4761da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
4771da177e4SLinus Torvalds {
4781da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
479cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
480cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
481cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
482cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
483cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
484cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
485cbf67842SDouglas Gilbert 				    __func__);
486cbf67842SDouglas Gilbert 		else
487cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
488cbf67842SDouglas Gilbert 				    __func__, cmd);
4891da177e4SLinus Torvalds 	}
4901da177e4SLinus Torvalds 	return -EINVAL;
4911da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
4921da177e4SLinus Torvalds }
4931da177e4SLinus Torvalds 
494cbf67842SDouglas Gilbert static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only,
495c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
4961da177e4SLinus Torvalds {
497cbf67842SDouglas Gilbert 	int k;
498cbf67842SDouglas Gilbert 	bool debug = !!(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts);
499cbf67842SDouglas Gilbert 
500cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
501cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
502cbf67842SDouglas Gilbert 		const char *cp = NULL;
503cbf67842SDouglas Gilbert 
504cbf67842SDouglas Gilbert 		switch (k) {
505cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
506cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
507cbf67842SDouglas Gilbert 					UA_RESET_ASC, POWER_ON_RESET_ASCQ);
508cbf67842SDouglas Gilbert 			if (debug)
509cbf67842SDouglas Gilbert 				cp = "power on reset";
510cbf67842SDouglas Gilbert 			break;
511cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
512cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
513cbf67842SDouglas Gilbert 					UA_RESET_ASC, BUS_RESET_ASCQ);
514cbf67842SDouglas Gilbert 			if (debug)
515cbf67842SDouglas Gilbert 				cp = "bus reset";
516cbf67842SDouglas Gilbert 			break;
517cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
518cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
519cbf67842SDouglas Gilbert 					UA_CHANGED_ASC, MODE_CHANGED_ASCQ);
520cbf67842SDouglas Gilbert 			if (debug)
521cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
522cbf67842SDouglas Gilbert 			break;
523cbf67842SDouglas Gilbert 		default:
524cbf67842SDouglas Gilbert 			pr_warn("%s: unexpected unit attention code=%d\n",
525cbf67842SDouglas Gilbert 				__func__, k);
526cbf67842SDouglas Gilbert 			if (debug)
527cbf67842SDouglas Gilbert 				cp = "unknown";
528cbf67842SDouglas Gilbert 			break;
529cbf67842SDouglas Gilbert 		}
530cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
531cbf67842SDouglas Gilbert 		if (debug)
532cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
533cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
534cbf67842SDouglas Gilbert 				   my_name, cp);
5351da177e4SLinus Torvalds 		return check_condition_result;
5361da177e4SLinus Torvalds 	}
537cbf67842SDouglas Gilbert 	if ((UAS_TUR == uas_only) && devip->stopped) {
538cbf67842SDouglas Gilbert 		mk_sense_buffer(SCpnt, NOT_READY, LOGICAL_UNIT_NOT_READY,
539c65b1445SDouglas Gilbert 				0x2);
540cbf67842SDouglas Gilbert 		if (debug)
541cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
542cbf67842SDouglas Gilbert 				    "%s reports: Not ready: %s\n", my_name,
543cbf67842SDouglas Gilbert 				    "initializing command required");
544c65b1445SDouglas Gilbert 		return check_condition_result;
545c65b1445SDouglas Gilbert 	}
5461da177e4SLinus Torvalds 	return 0;
5471da177e4SLinus Torvalds }
5481da177e4SLinus Torvalds 
5491da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
5501da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
5511da177e4SLinus Torvalds 				int arr_len)
5521da177e4SLinus Torvalds {
55321a61829SFUJITA Tomonori 	int act_len;
554072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
5551da177e4SLinus Torvalds 
556072d0bb3SFUJITA Tomonori 	if (!sdb->length)
5571da177e4SLinus Torvalds 		return 0;
558072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
5591da177e4SLinus Torvalds 		return (DID_ERROR << 16);
56021a61829SFUJITA Tomonori 
56121a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
56221a61829SFUJITA Tomonori 				      arr, arr_len);
56321a61829SFUJITA Tomonori 	sdb->resid = scsi_bufflen(scp) - act_len;
56421a61829SFUJITA Tomonori 
5651da177e4SLinus Torvalds 	return 0;
5661da177e4SLinus Torvalds }
5671da177e4SLinus Torvalds 
5681da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */
5691da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
57021a61829SFUJITA Tomonori 			       int arr_len)
5711da177e4SLinus Torvalds {
57221a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
5731da177e4SLinus Torvalds 		return 0;
574072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
5751da177e4SLinus Torvalds 		return -1;
57621a61829SFUJITA Tomonori 
57721a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
5781da177e4SLinus Torvalds }
5791da177e4SLinus Torvalds 
5801da177e4SLinus Torvalds 
5811da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux   ";
5821da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug      ";
583cbf67842SDouglas Gilbert static const char *inq_product_rev = "0184";	/* version less '.' */
5841da177e4SLinus Torvalds 
585cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
5865a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
5875a09e398SHannes Reinecke 			   int target_dev_id, int dev_id_num,
5885a09e398SHannes Reinecke 			   const char * dev_id_str,
589c65b1445SDouglas Gilbert 			   int dev_id_str_len)
5901da177e4SLinus Torvalds {
591c65b1445SDouglas Gilbert 	int num, port_a;
592c65b1445SDouglas Gilbert 	char b[32];
5931da177e4SLinus Torvalds 
594c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
5951da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
5961da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
5971da177e4SLinus Torvalds 	arr[1] = 0x1;
5981da177e4SLinus Torvalds 	arr[2] = 0x0;
5991da177e4SLinus Torvalds 	memcpy(&arr[4], inq_vendor_id, 8);
6001da177e4SLinus Torvalds 	memcpy(&arr[12], inq_product_id, 16);
6011da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
6021da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
6031da177e4SLinus Torvalds 	arr[3] = num;
6041da177e4SLinus Torvalds 	num += 4;
605c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
606c65b1445SDouglas Gilbert 		/* NAA-5, Logical unit identifier (binary) */
607c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* binary (not necessarily sas) */
608c65b1445SDouglas Gilbert 		arr[num++] = 0x3;	/* PIV=0, lu, naa */
609c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
610c65b1445SDouglas Gilbert 		arr[num++] = 0x8;
611c65b1445SDouglas Gilbert 		arr[num++] = 0x53;  /* naa-5 ieee company id=0x333333 (fake) */
612c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
613c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
614c65b1445SDouglas Gilbert 		arr[num++] = 0x30;
615c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 24);
616c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 16) & 0xff;
617c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 8) & 0xff;
618c65b1445SDouglas Gilbert 		arr[num++] = dev_id_num & 0xff;
619c65b1445SDouglas Gilbert 		/* Target relative port number */
620c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
621c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
622c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
623c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
624c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
625c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
626c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
627c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
628c65b1445SDouglas Gilbert 	}
629c65b1445SDouglas Gilbert 	/* NAA-5, Target port identifier */
630c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
631c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
632c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
633c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
634c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
635c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
636c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
637c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
638c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
639c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
640c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
641c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
6425a09e398SHannes Reinecke 	/* NAA-5, Target port group identifier */
6435a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
6445a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
6455a09e398SHannes Reinecke 	arr[num++] = 0x0;
6465a09e398SHannes Reinecke 	arr[num++] = 0x4;
6475a09e398SHannes Reinecke 	arr[num++] = 0;
6485a09e398SHannes Reinecke 	arr[num++] = 0;
6495a09e398SHannes Reinecke 	arr[num++] = (port_group_id >> 8) & 0xff;
6505a09e398SHannes Reinecke 	arr[num++] = port_group_id & 0xff;
651c65b1445SDouglas Gilbert 	/* NAA-5, Target device identifier */
652c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
653c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
654c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
655c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
656c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
657c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
658c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
659c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
660c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 24);
661c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 16) & 0xff;
662c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 8) & 0xff;
663c65b1445SDouglas Gilbert 	arr[num++] = target_dev_id & 0xff;
664c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
665c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
666c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
667c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
668c65b1445SDouglas Gilbert 	arr[num++] = 24;
669c65b1445SDouglas Gilbert 	memcpy(arr + num, "naa.52222220", 12);
670c65b1445SDouglas Gilbert 	num += 12;
671c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
672c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
673c65b1445SDouglas Gilbert 	num += 8;
674c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
675c65b1445SDouglas Gilbert 	num += 4;
676c65b1445SDouglas Gilbert 	return num;
677c65b1445SDouglas Gilbert }
678c65b1445SDouglas Gilbert 
679c65b1445SDouglas Gilbert 
680c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
681c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
682c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
683c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
684c65b1445SDouglas Gilbert };
685c65b1445SDouglas Gilbert 
686cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
687c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr)
688c65b1445SDouglas Gilbert {
689c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
690c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
691c65b1445SDouglas Gilbert }
692c65b1445SDouglas Gilbert 
693cbf67842SDouglas Gilbert /* Management network addresses VPD page */
694c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr)
695c65b1445SDouglas Gilbert {
696c65b1445SDouglas Gilbert 	int num = 0;
697c65b1445SDouglas Gilbert 	const char * na1 = "https://www.kernel.org/config";
698c65b1445SDouglas Gilbert 	const char * na2 = "http://www.kernel.org/log";
699c65b1445SDouglas Gilbert 	int plen, olen;
700c65b1445SDouglas Gilbert 
701c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
702c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
703c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
704c65b1445SDouglas Gilbert 	olen = strlen(na1);
705c65b1445SDouglas Gilbert 	plen = olen + 1;
706c65b1445SDouglas Gilbert 	if (plen % 4)
707c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
708c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
709c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
710c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
711c65b1445SDouglas Gilbert 	num += plen;
712c65b1445SDouglas Gilbert 
713c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
714c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
715c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
716c65b1445SDouglas Gilbert 	olen = strlen(na2);
717c65b1445SDouglas Gilbert 	plen = olen + 1;
718c65b1445SDouglas Gilbert 	if (plen % 4)
719c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
720c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
721c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
722c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
723c65b1445SDouglas Gilbert 	num += plen;
724c65b1445SDouglas Gilbert 
725c65b1445SDouglas Gilbert 	return num;
726c65b1445SDouglas Gilbert }
727c65b1445SDouglas Gilbert 
728c65b1445SDouglas Gilbert /* SCSI ports VPD page */
729c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
730c65b1445SDouglas Gilbert {
731c65b1445SDouglas Gilbert 	int num = 0;
732c65b1445SDouglas Gilbert 	int port_a, port_b;
733c65b1445SDouglas Gilbert 
734c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
735c65b1445SDouglas Gilbert 	port_b = port_a + 1;
736c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
737c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
738c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
739c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
740c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
741c65b1445SDouglas Gilbert 	num += 6;
742c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
743c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
744c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
745c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
746c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
747c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
748c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
749c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
750c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
751c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
752c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
753c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
754c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
755c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
756c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
757c65b1445SDouglas Gilbert 
758c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
759c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
760c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
761c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
762c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
763c65b1445SDouglas Gilbert 	num += 6;
764c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
765c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
766c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
767c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
768c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
769c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
770c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
771c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
772c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
773c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
774c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
775c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 24);
776c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 16) & 0xff;
777c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 8) & 0xff;
778c65b1445SDouglas Gilbert 	arr[num++] = port_b & 0xff;
779c65b1445SDouglas Gilbert 
780c65b1445SDouglas Gilbert 	return num;
781c65b1445SDouglas Gilbert }
782c65b1445SDouglas Gilbert 
783c65b1445SDouglas Gilbert 
784c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
785c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
786c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
787c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
788c65b1445SDouglas Gilbert '1','2','3','4',
789c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
790c65b1445SDouglas Gilbert 0xec,0,0,0,
791c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
792c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
793c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
794c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
795c65b1445SDouglas Gilbert 0x53,0x41,
796c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
797c65b1445SDouglas Gilbert 0x20,0x20,
798c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
799c65b1445SDouglas Gilbert 0x10,0x80,
800c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
801c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
802c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
803c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
804c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
805c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
806c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
807c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
808c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
809c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
810c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
811c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
812c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
813c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
814c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
815c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
816c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
817c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
818c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
819c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
820c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
821c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
822c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
823c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
824c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
825c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
826c65b1445SDouglas Gilbert };
827c65b1445SDouglas Gilbert 
828cbf67842SDouglas Gilbert /* ATA Information VPD page */
829c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr)
830c65b1445SDouglas Gilbert {
831c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
832c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
833c65b1445SDouglas Gilbert }
834c65b1445SDouglas Gilbert 
835c65b1445SDouglas Gilbert 
836c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
8371e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
8381e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8391e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8401e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
841c65b1445SDouglas Gilbert };
842c65b1445SDouglas Gilbert 
843cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
844c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr)
845c65b1445SDouglas Gilbert {
846ea61fca5SMartin K. Petersen 	unsigned int gran;
847ea61fca5SMartin K. Petersen 
848c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
849e308b3d1SMartin K. Petersen 
850e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
851ea61fca5SMartin K. Petersen 	gran = 1 << scsi_debug_physblk_exp;
852ea61fca5SMartin K. Petersen 	arr[2] = (gran >> 8) & 0xff;
853ea61fca5SMartin K. Petersen 	arr[3] = gran & 0xff;
854e308b3d1SMartin K. Petersen 
855e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
856c65b1445SDouglas Gilbert 	if (sdebug_store_sectors > 0x400) {
857c65b1445SDouglas Gilbert 		arr[4] = (sdebug_store_sectors >> 24) & 0xff;
858c65b1445SDouglas Gilbert 		arr[5] = (sdebug_store_sectors >> 16) & 0xff;
859c65b1445SDouglas Gilbert 		arr[6] = (sdebug_store_sectors >> 8) & 0xff;
860c65b1445SDouglas Gilbert 		arr[7] = sdebug_store_sectors & 0xff;
861c65b1445SDouglas Gilbert 	}
86244d92694SMartin K. Petersen 
863e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
864e308b3d1SMartin K. Petersen 	put_unaligned_be32(scsi_debug_opt_blks, &arr[8]);
865e308b3d1SMartin K. Petersen 
8665b94e232SMartin K. Petersen 	if (scsi_debug_lbpu) {
867e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
8686014759cSMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]);
869e308b3d1SMartin K. Petersen 
870e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
87144d92694SMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
87244d92694SMartin K. Petersen 	}
87344d92694SMartin K. Petersen 
874e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
87544d92694SMartin K. Petersen 	if (scsi_debug_unmap_alignment) {
87644d92694SMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
87744d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
87844d92694SMartin K. Petersen 	}
87944d92694SMartin K. Petersen 
880e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
88144d92694SMartin K. Petersen 	put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
8826014759cSMartin K. Petersen 
8835b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
8845b94e232SMartin K. Petersen 	put_unaligned_be64(scsi_debug_write_same_length, &arr[32]);
8855b94e232SMartin K. Petersen 
8865b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
88744d92694SMartin K. Petersen 
888c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
8891da177e4SLinus Torvalds }
8901da177e4SLinus Torvalds 
8911e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
892eac6e8e4SMatthew Wilcox static int inquiry_evpd_b1(unsigned char *arr)
893eac6e8e4SMatthew Wilcox {
894eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
895eac6e8e4SMatthew Wilcox 	arr[0] = 0;
8961e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
8971e49f785SDouglas Gilbert 	arr[2] = 0;
8981e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
899eac6e8e4SMatthew Wilcox 
900eac6e8e4SMatthew Wilcox 	return 0x3c;
901eac6e8e4SMatthew Wilcox }
9021da177e4SLinus Torvalds 
903be1dd78dSEric Sandeen /* Logical block provisioning VPD page (SBC-3) */
9046014759cSMartin K. Petersen static int inquiry_evpd_b2(unsigned char *arr)
9056014759cSMartin K. Petersen {
9063f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
9076014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
9086014759cSMartin K. Petersen 
9095b94e232SMartin K. Petersen 	if (scsi_debug_lbpu)
9106014759cSMartin K. Petersen 		arr[1] = 1 << 7;
9116014759cSMartin K. Petersen 
9125b94e232SMartin K. Petersen 	if (scsi_debug_lbpws)
9136014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
9146014759cSMartin K. Petersen 
9155b94e232SMartin K. Petersen 	if (scsi_debug_lbpws10)
9165b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
9175b94e232SMartin K. Petersen 
918be1dd78dSEric Sandeen 	if (scsi_debug_lbprz)
919be1dd78dSEric Sandeen 		arr[1] |= 1 << 2;
920be1dd78dSEric Sandeen 
9213f0bc3b3SMartin K. Petersen 	return 0x4;
9226014759cSMartin K. Petersen }
9236014759cSMartin K. Petersen 
9241da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
925c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
9261da177e4SLinus Torvalds 
9271da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd *scp, int target,
9281da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
9291da177e4SLinus Torvalds {
9301da177e4SLinus Torvalds 	unsigned char pq_pdt;
9315a09e398SHannes Reinecke 	unsigned char * arr;
93201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
9335a09e398SHannes Reinecke 	int alloc_len, n, ret;
9341da177e4SLinus Torvalds 
9351da177e4SLinus Torvalds 	alloc_len = (cmd[3] << 8) + cmd[4];
9366f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
9376f3cbf55SDouglas Gilbert 	if (! arr)
9386f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
939c65b1445SDouglas Gilbert 	if (devip->wlun)
940c65b1445SDouglas Gilbert 		pq_pdt = 0x1e;	/* present, wlun */
941c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (0 == devip->lun))
942c65b1445SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, no device type */
943c65b1445SDouglas Gilbert 	else
9441da177e4SLinus Torvalds 		pq_pdt = (scsi_debug_ptype & 0x1f);
9451da177e4SLinus Torvalds 	arr[0] = pq_pdt;
9461da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
947cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
9481da177e4SLinus Torvalds 			       	0);
9495a09e398SHannes Reinecke 		kfree(arr);
9501da177e4SLinus Torvalds 		return check_condition_result;
9511da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
9525a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
953c65b1445SDouglas Gilbert 		char lu_id_str[6];
954c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
9551da177e4SLinus Torvalds 
9565a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
9575a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
95823183910SDouglas Gilbert 		if (0 == scsi_debug_vpd_use_hostno)
95923183910SDouglas Gilbert 			host_no = 0;
960c65b1445SDouglas Gilbert 		lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
961c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
962c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
963c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
964c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
9651da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
966c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
967c65b1445SDouglas Gilbert 			n = 4;
968c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
969c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
970c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
971c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
972c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
973c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
974c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
975c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
976c65b1445SDouglas Gilbert 			arr[n++] = 0x89;  /* ATA information */
977c65b1445SDouglas Gilbert 			arr[n++] = 0xb0;  /* Block limits (SBC) */
978eac6e8e4SMatthew Wilcox 			arr[n++] = 0xb1;  /* Block characteristics (SBC) */
9795b94e232SMartin K. Petersen 			if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
9805b94e232SMartin K. Petersen 				arr[n++] = 0xb2;
981c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
9821da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
983c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
9841da177e4SLinus Torvalds 			arr[3] = len;
985c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
9861da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
987c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
9885a09e398SHannes Reinecke 			arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
9895a09e398SHannes Reinecke 						 target_dev_id, lu_id_num,
9905a09e398SHannes Reinecke 						 lu_id_str, len);
991c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
992c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
993c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_84(&arr[4]);
994c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
995c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
996c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_85(&arr[4]);
997c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
998c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
999c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
1000c6a44287SMartin K. Petersen 			if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
1001c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1002c6a44287SMartin K. Petersen 			else if (scsi_debug_dif)
1003c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1004c6a44287SMartin K. Petersen 			else
1005c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1006c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1007c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1008c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1009c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1010c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1011c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1012c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1013c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1014c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1015c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1016c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1017c65b1445SDouglas Gilbert 		} else if (0x89 == cmd[2]) { /* ATA information */
1018c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1019c65b1445SDouglas Gilbert 			n = inquiry_evpd_89(&arr[4]);
1020c65b1445SDouglas Gilbert 			arr[2] = (n >> 8);
1021c65b1445SDouglas Gilbert 			arr[3] = (n & 0xff);
1022c65b1445SDouglas Gilbert 		} else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1023c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1024c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_b0(&arr[4]);
1025eac6e8e4SMatthew Wilcox 		} else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
1026eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
1027eac6e8e4SMatthew Wilcox 			arr[3] = inquiry_evpd_b1(&arr[4]);
10285b94e232SMartin K. Petersen 		} else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
10296014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
10306014759cSMartin K. Petersen 			arr[3] = inquiry_evpd_b2(&arr[4]);
10311da177e4SLinus Torvalds 		} else {
10321da177e4SLinus Torvalds 			/* Illegal request, invalid field in cdb */
1033cbf67842SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
10341da177e4SLinus Torvalds 					INVALID_FIELD_IN_CDB, 0);
10355a09e398SHannes Reinecke 			kfree(arr);
10361da177e4SLinus Torvalds 			return check_condition_result;
10371da177e4SLinus Torvalds 		}
1038c65b1445SDouglas Gilbert 		len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
10395a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1040c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
10415a09e398SHannes Reinecke 		kfree(arr);
10425a09e398SHannes Reinecke 		return ret;
10431da177e4SLinus Torvalds 	}
10441da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1045d986788bSMartin Pitt 	arr[1] = scsi_debug_removable ? 0x80 : 0;	/* Removable disk */
10461da177e4SLinus Torvalds 	arr[2] = scsi_debug_scsi_level;
10471da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
10481da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1049c6a44287SMartin K. Petersen 	arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
10505a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno)
10515a09e398SHannes Reinecke 		arr[5] = 0x10; /* claim: implicit TGPS */
1052c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
10531da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1054c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
10551da177e4SLinus Torvalds 	memcpy(&arr[8], inq_vendor_id, 8);
10561da177e4SLinus Torvalds 	memcpy(&arr[16], inq_product_id, 16);
10571da177e4SLinus Torvalds 	memcpy(&arr[32], inq_product_rev, 4);
10581da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1059e46b0344SDouglas Gilbert 	arr[58] = 0x0; arr[59] = 0xa2;  /* SAM-5 rev 4 */
1060e46b0344SDouglas Gilbert 	arr[60] = 0x4; arr[61] = 0x68;  /* SPC-4 rev 37 */
1061c65b1445SDouglas Gilbert 	n = 62;
10621da177e4SLinus Torvalds 	if (scsi_debug_ptype == 0) {
1063e46b0344SDouglas Gilbert 		arr[n++] = 0x4; arr[n++] = 0xc5; /* SBC-4 rev 36 */
10641da177e4SLinus Torvalds 	} else if (scsi_debug_ptype == 1) {
1065e46b0344SDouglas Gilbert 		arr[n++] = 0x5; arr[n++] = 0x25; /* SSC-4 rev 3 */
10661da177e4SLinus Torvalds 	}
1067e46b0344SDouglas Gilbert 	arr[n++] = 0x20; arr[n++] = 0xe6;  /* SPL-3 rev 7 */
10685a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
10691da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
10705a09e398SHannes Reinecke 	kfree(arr);
10715a09e398SHannes Reinecke 	return ret;
10721da177e4SLinus Torvalds }
10731da177e4SLinus Torvalds 
10741da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp,
10751da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip)
10761da177e4SLinus Torvalds {
10771da177e4SLinus Torvalds 	unsigned char * sbuff;
107801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1079cbf67842SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
1080c65b1445SDouglas Gilbert 	int want_dsense;
10811da177e4SLinus Torvalds 	int len = 18;
10821da177e4SLinus Torvalds 
1083c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1084c65b1445SDouglas Gilbert 	want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
1085cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
1086c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1087c65b1445SDouglas Gilbert 		if (want_dsense) {
1088c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1089c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1090c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
1091c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
1092c65b1445SDouglas Gilbert 		} else {
1093c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1094c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1095c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1096c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
1097c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
1098c65b1445SDouglas Gilbert 		}
1099c65b1445SDouglas Gilbert 	} else {
1100cbf67842SDouglas Gilbert 		memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
11011da177e4SLinus Torvalds 		if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
11021da177e4SLinus Torvalds 			/* DESC bit set and sense_buff in fixed format */
1103c65b1445SDouglas Gilbert 			memset(arr, 0, sizeof(arr));
11041da177e4SLinus Torvalds 			arr[0] = 0x72;
11051da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
11061da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
11071da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
11081da177e4SLinus Torvalds 			len = 8;
1109c65b1445SDouglas Gilbert 		}
1110c65b1445SDouglas Gilbert 	}
1111cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
11121da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
11131da177e4SLinus Torvalds }
11141da177e4SLinus Torvalds 
1115c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp,
1116c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
1117c65b1445SDouglas Gilbert {
111801123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1119c65b1445SDouglas Gilbert 	int power_cond, errsts, start;
1120c65b1445SDouglas Gilbert 
1121cbf67842SDouglas Gilbert 	errsts = check_readiness(scp, UAS_ONLY, devip);
1122cbf67842SDouglas Gilbert 	if (errsts)
1123c65b1445SDouglas Gilbert 		return errsts;
1124c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1125c65b1445SDouglas Gilbert 	if (power_cond) {
1126cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1127c65b1445SDouglas Gilbert 			       	0);
1128c65b1445SDouglas Gilbert 		return check_condition_result;
1129c65b1445SDouglas Gilbert 	}
1130c65b1445SDouglas Gilbert 	start = cmd[4] & 1;
1131c65b1445SDouglas Gilbert 	if (start == devip->stopped)
1132c65b1445SDouglas Gilbert 		devip->stopped = !start;
1133c65b1445SDouglas Gilbert 	return 0;
1134c65b1445SDouglas Gilbert }
1135c65b1445SDouglas Gilbert 
113628898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
113728898873SFUJITA Tomonori {
113828898873SFUJITA Tomonori 	if (scsi_debug_virtual_gb > 0)
11395447ed6cSDouglas Gilbert 		return (sector_t)scsi_debug_virtual_gb *
11405447ed6cSDouglas Gilbert 			(1073741824 / scsi_debug_sector_size);
114128898873SFUJITA Tomonori 	else
114228898873SFUJITA Tomonori 		return sdebug_store_sectors;
114328898873SFUJITA Tomonori }
114428898873SFUJITA Tomonori 
11451da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
11461da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp,
11471da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
11481da177e4SLinus Torvalds {
11491da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1150c65b1445SDouglas Gilbert 	unsigned int capac;
11511da177e4SLinus Torvalds 	int errsts;
11521da177e4SLinus Torvalds 
1153cbf67842SDouglas Gilbert 	errsts = check_readiness(scp, UAS_ONLY, devip);
1154cbf67842SDouglas Gilbert 	if (errsts)
11551da177e4SLinus Torvalds 		return errsts;
1156c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
115728898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
11581da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1159c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1160c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
11611da177e4SLinus Torvalds 		arr[0] = (capac >> 24);
11621da177e4SLinus Torvalds 		arr[1] = (capac >> 16) & 0xff;
11631da177e4SLinus Torvalds 		arr[2] = (capac >> 8) & 0xff;
11641da177e4SLinus Torvalds 		arr[3] = capac & 0xff;
1165c65b1445SDouglas Gilbert 	} else {
1166c65b1445SDouglas Gilbert 		arr[0] = 0xff;
1167c65b1445SDouglas Gilbert 		arr[1] = 0xff;
1168c65b1445SDouglas Gilbert 		arr[2] = 0xff;
1169c65b1445SDouglas Gilbert 		arr[3] = 0xff;
1170c65b1445SDouglas Gilbert 	}
1171597136abSMartin K. Petersen 	arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
1172597136abSMartin K. Petersen 	arr[7] = scsi_debug_sector_size & 0xff;
11731da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
11741da177e4SLinus Torvalds }
11751da177e4SLinus Torvalds 
1176c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1177c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp,
1178c65b1445SDouglas Gilbert 			  struct sdebug_dev_info * devip)
1179c65b1445SDouglas Gilbert {
118001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1181c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1182c65b1445SDouglas Gilbert 	unsigned long long capac;
1183c65b1445SDouglas Gilbert 	int errsts, k, alloc_len;
1184c65b1445SDouglas Gilbert 
1185cbf67842SDouglas Gilbert 	errsts = check_readiness(scp, UAS_ONLY, devip);
1186cbf67842SDouglas Gilbert 	if (errsts)
1187c65b1445SDouglas Gilbert 		return errsts;
1188c65b1445SDouglas Gilbert 	alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1189c65b1445SDouglas Gilbert 		     + cmd[13]);
1190c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
119128898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1192c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1193c65b1445SDouglas Gilbert 	capac = sdebug_capacity - 1;
1194c65b1445SDouglas Gilbert 	for (k = 0; k < 8; ++k, capac >>= 8)
1195c65b1445SDouglas Gilbert 		arr[7 - k] = capac & 0xff;
1196597136abSMartin K. Petersen 	arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
1197597136abSMartin K. Petersen 	arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
1198597136abSMartin K. Petersen 	arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
1199597136abSMartin K. Petersen 	arr[11] = scsi_debug_sector_size & 0xff;
1200ea61fca5SMartin K. Petersen 	arr[13] = scsi_debug_physblk_exp & 0xf;
1201ea61fca5SMartin K. Petersen 	arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
120244d92694SMartin K. Petersen 
1203be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
12045b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1205be1dd78dSEric Sandeen 		if (scsi_debug_lbprz)
1206be1dd78dSEric Sandeen 			arr[14] |= 0x40; /* LBPRZ */
1207be1dd78dSEric Sandeen 	}
120844d92694SMartin K. Petersen 
1209ea61fca5SMartin K. Petersen 	arr[15] = scsi_debug_lowest_aligned & 0xff;
1210c6a44287SMartin K. Petersen 
1211c6a44287SMartin K. Petersen 	if (scsi_debug_dif) {
1212c6a44287SMartin K. Petersen 		arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
1213c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1214c6a44287SMartin K. Petersen 	}
1215c6a44287SMartin K. Petersen 
1216c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1217c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1218c65b1445SDouglas Gilbert }
1219c65b1445SDouglas Gilbert 
12205a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
12215a09e398SHannes Reinecke 
12225a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp,
12235a09e398SHannes Reinecke 			      struct sdebug_dev_info * devip)
12245a09e398SHannes Reinecke {
122501123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
12265a09e398SHannes Reinecke 	unsigned char * arr;
12275a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
12285a09e398SHannes Reinecke 	int n, ret, alen, rlen;
12295a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
12305a09e398SHannes Reinecke 
12315a09e398SHannes Reinecke 	alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
12325a09e398SHannes Reinecke 		+ cmd[9]);
12335a09e398SHannes Reinecke 
12346f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
12356f3cbf55SDouglas Gilbert 	if (! arr)
12366f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
12375a09e398SHannes Reinecke 	/*
12385a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
12395a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
12405a09e398SHannes Reinecke 	 * So we create two port groups with one port each
12415a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
12425a09e398SHannes Reinecke 	 */
12435a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
12445a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
12455a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
12465a09e398SHannes Reinecke 	    (devip->channel & 0x7f);
12475a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
12485a09e398SHannes Reinecke 	    (devip->channel & 0x7f) + 0x80;
12495a09e398SHannes Reinecke 
12505a09e398SHannes Reinecke 	/*
12515a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
12525a09e398SHannes Reinecke 	 */
12535a09e398SHannes Reinecke 	n = 4;
12545a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno) {
12555a09e398SHannes Reinecke 	    arr[n++] = host_no % 3; /* Asymm access state */
12565a09e398SHannes Reinecke 	    arr[n++] = 0x0F; /* claim: all states are supported */
12575a09e398SHannes Reinecke 	} else {
12585a09e398SHannes Reinecke 	    arr[n++] = 0x0; /* Active/Optimized path */
12595a09e398SHannes Reinecke 	    arr[n++] = 0x01; /* claim: only support active/optimized paths */
12605a09e398SHannes Reinecke 	}
12615a09e398SHannes Reinecke 	arr[n++] = (port_group_a >> 8) & 0xff;
12625a09e398SHannes Reinecke 	arr[n++] = port_group_a & 0xff;
12635a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
12645a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
12655a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
12665a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
12675a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
12685a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
12695a09e398SHannes Reinecke 	arr[n++] = (port_a >> 8) & 0xff;
12705a09e398SHannes Reinecke 	arr[n++] = port_a & 0xff;
12715a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
12725a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
12735a09e398SHannes Reinecke 	arr[n++] = (port_group_b >> 8) & 0xff;
12745a09e398SHannes Reinecke 	arr[n++] = port_group_b & 0xff;
12755a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
12765a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
12775a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
12785a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
12795a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
12805a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
12815a09e398SHannes Reinecke 	arr[n++] = (port_b >> 8) & 0xff;
12825a09e398SHannes Reinecke 	arr[n++] = port_b & 0xff;
12835a09e398SHannes Reinecke 
12845a09e398SHannes Reinecke 	rlen = n - 4;
12855a09e398SHannes Reinecke 	arr[0] = (rlen >> 24) & 0xff;
12865a09e398SHannes Reinecke 	arr[1] = (rlen >> 16) & 0xff;
12875a09e398SHannes Reinecke 	arr[2] = (rlen >> 8) & 0xff;
12885a09e398SHannes Reinecke 	arr[3] = rlen & 0xff;
12895a09e398SHannes Reinecke 
12905a09e398SHannes Reinecke 	/*
12915a09e398SHannes Reinecke 	 * Return the smallest value of either
12925a09e398SHannes Reinecke 	 * - The allocated length
12935a09e398SHannes Reinecke 	 * - The constructed command length
12945a09e398SHannes Reinecke 	 * - The maximum array size
12955a09e398SHannes Reinecke 	 */
12965a09e398SHannes Reinecke 	rlen = min(alen,n);
12975a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
12985a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
12995a09e398SHannes Reinecke 	kfree(arr);
13005a09e398SHannes Reinecke 	return ret;
13015a09e398SHannes Reinecke }
13025a09e398SHannes Reinecke 
13031da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
13041da177e4SLinus Torvalds 
13051da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
13061da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
13071da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
13081da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
13091da177e4SLinus Torvalds 
13101da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
13111da177e4SLinus Torvalds 	if (1 == pcontrol)
13121da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
13131da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
13141da177e4SLinus Torvalds }
13151da177e4SLinus Torvalds 
13161da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
13171da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
13181da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
13191da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
13201da177e4SLinus Torvalds 
13211da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
13221da177e4SLinus Torvalds 	if (1 == pcontrol)
13231da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
13241da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
13251da177e4SLinus Torvalds }
13261da177e4SLinus Torvalds 
13271da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target)
13281da177e4SLinus Torvalds {       /* Format device page for mode_sense */
13291da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
13301da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
13311da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
13321da177e4SLinus Torvalds 
13331da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
13341da177e4SLinus Torvalds 	p[10] = (sdebug_sectors_per >> 8) & 0xff;
13351da177e4SLinus Torvalds 	p[11] = sdebug_sectors_per & 0xff;
1336597136abSMartin K. Petersen 	p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1337597136abSMartin K. Petersen 	p[13] = scsi_debug_sector_size & 0xff;
1338d986788bSMartin Pitt 	if (scsi_debug_removable)
13391da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
13401da177e4SLinus Torvalds 	if (1 == pcontrol)
13411da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
13421da177e4SLinus Torvalds 	return sizeof(format_pg);
13431da177e4SLinus Torvalds }
13441da177e4SLinus Torvalds 
13451da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
13461da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
1347cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1348cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1349cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
13501da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
13511da177e4SLinus Torvalds 
1352cbf67842SDouglas Gilbert 	if (SCSI_DEBUG_OPT_N_WCE & scsi_debug_opts)
1353cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
13541da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
13551da177e4SLinus Torvalds 	if (1 == pcontrol)
1356cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1357cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
1358cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
13591da177e4SLinus Torvalds 	return sizeof(caching_pg);
13601da177e4SLinus Torvalds }
13611da177e4SLinus Torvalds 
13621da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
13631da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
1364c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1365c65b1445SDouglas Gilbert 				        0, 0, 0, 0};
1366c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
13671da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
13681da177e4SLinus Torvalds 
13691da177e4SLinus Torvalds 	if (scsi_debug_dsense)
13701da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
1371c65b1445SDouglas Gilbert 	else
1372c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
1373c6a44287SMartin K. Petersen 
1374c6a44287SMartin K. Petersen 	if (scsi_debug_ato)
1375c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1376c6a44287SMartin K. Petersen 
13771da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
13781da177e4SLinus Torvalds 	if (1 == pcontrol)
1379c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1380c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1381c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
13821da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
13831da177e4SLinus Torvalds }
13841da177e4SLinus Torvalds 
1385c65b1445SDouglas Gilbert 
13861da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
13871da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
1388c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
13891da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
1390c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1391c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
1392c65b1445SDouglas Gilbert 
13931da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
13941da177e4SLinus Torvalds 	if (1 == pcontrol)
1395c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1396c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1397c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
13981da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
13991da177e4SLinus Torvalds }
14001da177e4SLinus Torvalds 
1401c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1402c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
1403c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1404c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1405c65b1445SDouglas Gilbert 
1406c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1407c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1408c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1409c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
1410c65b1445SDouglas Gilbert }
1411c65b1445SDouglas Gilbert 
1412c65b1445SDouglas Gilbert 
1413c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1414c65b1445SDouglas Gilbert 			      int target_dev_id)
1415c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
1416c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1417c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1418c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1419c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1420c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
1421c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1422c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1423c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1424c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1425c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1426c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
1427c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1428c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1429c65b1445SDouglas Gilbert 		};
1430c65b1445SDouglas Gilbert 	int port_a, port_b;
1431c65b1445SDouglas Gilbert 
1432c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1433c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1434c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1435c65b1445SDouglas Gilbert 	p[20] = (port_a >> 24);
1436c65b1445SDouglas Gilbert 	p[21] = (port_a >> 16) & 0xff;
1437c65b1445SDouglas Gilbert 	p[22] = (port_a >> 8) & 0xff;
1438c65b1445SDouglas Gilbert 	p[23] = port_a & 0xff;
1439c65b1445SDouglas Gilbert 	p[48 + 20] = (port_b >> 24);
1440c65b1445SDouglas Gilbert 	p[48 + 21] = (port_b >> 16) & 0xff;
1441c65b1445SDouglas Gilbert 	p[48 + 22] = (port_b >> 8) & 0xff;
1442c65b1445SDouglas Gilbert 	p[48 + 23] = port_b & 0xff;
1443c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1444c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1445c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
1446c65b1445SDouglas Gilbert }
1447c65b1445SDouglas Gilbert 
1448c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1449c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
1450c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1451c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1452c65b1445SDouglas Gilbert 		};
1453c65b1445SDouglas Gilbert 
1454c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1455c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1456c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1457c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
1458c65b1445SDouglas Gilbert }
1459c65b1445SDouglas Gilbert 
14601da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
14611da177e4SLinus Torvalds 
14621da177e4SLinus Torvalds static int resp_mode_sense(struct scsi_cmnd * scp, int target,
14631da177e4SLinus Torvalds 			   struct sdebug_dev_info * devip)
14641da177e4SLinus Torvalds {
146523183910SDouglas Gilbert 	unsigned char dbd, llbaa;
146623183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
14671da177e4SLinus Torvalds 	unsigned char dev_spec;
146823183910SDouglas Gilbert 	int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
14691da177e4SLinus Torvalds 	unsigned char * ap;
14701da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
147101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
14721da177e4SLinus Torvalds 
1473cbf67842SDouglas Gilbert 	errsts = check_readiness(scp, UAS_ONLY, devip);
1474cbf67842SDouglas Gilbert 	if (errsts)
14751da177e4SLinus Torvalds 		return errsts;
147623183910SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);
14771da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
14781da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
14791da177e4SLinus Torvalds 	subpcode = cmd[3];
14801da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
148123183910SDouglas Gilbert 	llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
148223183910SDouglas Gilbert 	if ((0 == scsi_debug_ptype) && (0 == dbd))
148323183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
148423183910SDouglas Gilbert 	else
148523183910SDouglas Gilbert 		bd_len = 0;
14861da177e4SLinus Torvalds 	alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
14871da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
14881da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
1489cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
14901da177e4SLinus Torvalds 		return check_condition_result;
14911da177e4SLinus Torvalds 	}
1492c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1493c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
149423183910SDouglas Gilbert 	/* set DPOFUA bit for disks */
149523183910SDouglas Gilbert 	if (0 == scsi_debug_ptype)
149623183910SDouglas Gilbert 		dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
149723183910SDouglas Gilbert 	else
149823183910SDouglas Gilbert 		dev_spec = 0x0;
14991da177e4SLinus Torvalds 	if (msense_6) {
15001da177e4SLinus Torvalds 		arr[2] = dev_spec;
150123183910SDouglas Gilbert 		arr[3] = bd_len;
15021da177e4SLinus Torvalds 		offset = 4;
15031da177e4SLinus Torvalds 	} else {
15041da177e4SLinus Torvalds 		arr[3] = dev_spec;
150523183910SDouglas Gilbert 		if (16 == bd_len)
150623183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
150723183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
15081da177e4SLinus Torvalds 		offset = 8;
15091da177e4SLinus Torvalds 	}
15101da177e4SLinus Torvalds 	ap = arr + offset;
151128898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
151228898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
151328898873SFUJITA Tomonori 
151423183910SDouglas Gilbert 	if (8 == bd_len) {
151523183910SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe) {
151623183910SDouglas Gilbert 			ap[0] = 0xff;
151723183910SDouglas Gilbert 			ap[1] = 0xff;
151823183910SDouglas Gilbert 			ap[2] = 0xff;
151923183910SDouglas Gilbert 			ap[3] = 0xff;
152023183910SDouglas Gilbert 		} else {
152123183910SDouglas Gilbert 			ap[0] = (sdebug_capacity >> 24) & 0xff;
152223183910SDouglas Gilbert 			ap[1] = (sdebug_capacity >> 16) & 0xff;
152323183910SDouglas Gilbert 			ap[2] = (sdebug_capacity >> 8) & 0xff;
152423183910SDouglas Gilbert 			ap[3] = sdebug_capacity & 0xff;
152523183910SDouglas Gilbert 		}
1526597136abSMartin K. Petersen 		ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1527597136abSMartin K. Petersen 		ap[7] = scsi_debug_sector_size & 0xff;
152823183910SDouglas Gilbert 		offset += bd_len;
152923183910SDouglas Gilbert 		ap = arr + offset;
153023183910SDouglas Gilbert 	} else if (16 == bd_len) {
153123183910SDouglas Gilbert 		unsigned long long capac = sdebug_capacity;
153223183910SDouglas Gilbert 
153323183910SDouglas Gilbert         	for (k = 0; k < 8; ++k, capac >>= 8)
153423183910SDouglas Gilbert                 	ap[7 - k] = capac & 0xff;
1535597136abSMartin K. Petersen 		ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1536597136abSMartin K. Petersen 		ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1537597136abSMartin K. Petersen 		ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1538597136abSMartin K. Petersen 		ap[15] = scsi_debug_sector_size & 0xff;
153923183910SDouglas Gilbert 		offset += bd_len;
154023183910SDouglas Gilbert 		ap = arr + offset;
154123183910SDouglas Gilbert 	}
15421da177e4SLinus Torvalds 
1543c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1544c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
1545cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
15461da177e4SLinus Torvalds 			       	0);
15471da177e4SLinus Torvalds 		return check_condition_result;
15481da177e4SLinus Torvalds 	}
15491da177e4SLinus Torvalds 	switch (pcode) {
15501da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
15511da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
15521da177e4SLinus Torvalds 		offset += len;
15531da177e4SLinus Torvalds 		break;
15541da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
15551da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
15561da177e4SLinus Torvalds 		offset += len;
15571da177e4SLinus Torvalds 		break;
15581da177e4SLinus Torvalds         case 0x3:       /* Format device page, direct access */
15591da177e4SLinus Torvalds                 len = resp_format_pg(ap, pcontrol, target);
15601da177e4SLinus Torvalds                 offset += len;
15611da177e4SLinus Torvalds                 break;
15621da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
15631da177e4SLinus Torvalds 		len = resp_caching_pg(ap, pcontrol, target);
15641da177e4SLinus Torvalds 		offset += len;
15651da177e4SLinus Torvalds 		break;
15661da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
15671da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
15681da177e4SLinus Torvalds 		offset += len;
15691da177e4SLinus Torvalds 		break;
1570c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
1571c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
1572cbf67842SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
1573c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1574c65b1445SDouglas Gilbert 			return check_condition_result;
1575c65b1445SDouglas Gilbert 	        }
1576c65b1445SDouglas Gilbert 		len = 0;
1577c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
1578c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1579c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
1580c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1581c65b1445SDouglas Gilbert 						  target_dev_id);
1582c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
1583c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
1584c65b1445SDouglas Gilbert 		offset += len;
1585c65b1445SDouglas Gilbert 		break;
15861da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
15871da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
15881da177e4SLinus Torvalds 		offset += len;
15891da177e4SLinus Torvalds 		break;
15901da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
1591c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
15921da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
15931da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
15941da177e4SLinus Torvalds 			len += resp_format_pg(ap + len, pcontrol, target);
15951da177e4SLinus Torvalds 			len += resp_caching_pg(ap + len, pcontrol, target);
15961da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1597c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1598c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
1599c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1600c65b1445SDouglas Gilbert 						  target, target_dev_id);
1601c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
1602c65b1445SDouglas Gilbert 			}
16031da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
1604c65b1445SDouglas Gilbert 		} else {
1605cbf67842SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
1606c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1607c65b1445SDouglas Gilbert 			return check_condition_result;
1608c65b1445SDouglas Gilbert                 }
16091da177e4SLinus Torvalds 		offset += len;
16101da177e4SLinus Torvalds 		break;
16111da177e4SLinus Torvalds 	default:
1612cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
16131da177e4SLinus Torvalds 			       	0);
16141da177e4SLinus Torvalds 		return check_condition_result;
16151da177e4SLinus Torvalds 	}
16161da177e4SLinus Torvalds 	if (msense_6)
16171da177e4SLinus Torvalds 		arr[0] = offset - 1;
16181da177e4SLinus Torvalds 	else {
16191da177e4SLinus Torvalds 		arr[0] = ((offset - 2) >> 8) & 0xff;
16201da177e4SLinus Torvalds 		arr[1] = (offset - 2) & 0xff;
16211da177e4SLinus Torvalds 	}
16221da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
16231da177e4SLinus Torvalds }
16241da177e4SLinus Torvalds 
1625c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
1626c65b1445SDouglas Gilbert 
1627c65b1445SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1628c65b1445SDouglas Gilbert 			    struct sdebug_dev_info * devip)
1629c65b1445SDouglas Gilbert {
1630c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1631c65b1445SDouglas Gilbert 	int param_len, res, errsts, mpage;
1632c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
163301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1634c65b1445SDouglas Gilbert 
1635cbf67842SDouglas Gilbert 	errsts = check_readiness(scp, UAS_ONLY, devip);
1636cbf67842SDouglas Gilbert 	if (errsts)
1637c65b1445SDouglas Gilbert 		return errsts;
1638c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1639c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
1640c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
1641c65b1445SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1642c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1643cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
1644c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
1645c65b1445SDouglas Gilbert 		return check_condition_result;
1646c65b1445SDouglas Gilbert 	}
1647c65b1445SDouglas Gilbert         res = fetch_to_dev_buffer(scp, arr, param_len);
1648c65b1445SDouglas Gilbert         if (-1 == res)
1649c65b1445SDouglas Gilbert                 return (DID_ERROR << 16);
1650c65b1445SDouglas Gilbert         else if ((res < param_len) &&
1651c65b1445SDouglas Gilbert                  (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1652cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
1653cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
1654cbf67842SDouglas Gilbert 			    __func__, param_len, res);
1655c65b1445SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1656c65b1445SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
165723183910SDouglas Gilbert 	if (md_len > 2) {
1658cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
1659c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_PARAM_LIST, 0);
1660c65b1445SDouglas Gilbert 		return check_condition_result;
1661c65b1445SDouglas Gilbert 	}
1662c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
1663c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
1664c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
1665c65b1445SDouglas Gilbert 	if (ps) {
1666cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
1667c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_PARAM_LIST, 0);
1668c65b1445SDouglas Gilbert 		return check_condition_result;
1669c65b1445SDouglas Gilbert 	}
1670c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
1671c65b1445SDouglas Gilbert 	pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1672c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
1673c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
1674cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
1675c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
1676c65b1445SDouglas Gilbert 		return check_condition_result;
1677c65b1445SDouglas Gilbert 	}
1678c65b1445SDouglas Gilbert 	switch (mpage) {
1679cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
1680cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
1681cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
1682cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
1683cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
1684cbf67842SDouglas Gilbert 		}
1685cbf67842SDouglas Gilbert 		break;
1686c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
1687c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
1688c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
1689c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
1690c65b1445SDouglas Gilbert 			scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1691cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
1692c65b1445SDouglas Gilbert 		}
1693c65b1445SDouglas Gilbert 		break;
1694c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
1695c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
1696c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
1697c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
1698cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
1699c65b1445SDouglas Gilbert 		}
1700c65b1445SDouglas Gilbert 		break;
1701c65b1445SDouglas Gilbert 	default:
1702c65b1445SDouglas Gilbert 		break;
1703c65b1445SDouglas Gilbert 	}
1704cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST,
1705c65b1445SDouglas Gilbert 			INVALID_FIELD_IN_PARAM_LIST, 0);
1706c65b1445SDouglas Gilbert 	return check_condition_result;
1707cbf67842SDouglas Gilbert set_mode_changed_ua:
1708cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
1709cbf67842SDouglas Gilbert 	return 0;
1710c65b1445SDouglas Gilbert }
1711c65b1445SDouglas Gilbert 
1712c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr)
1713c65b1445SDouglas Gilbert {
1714c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1715c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
1716c65b1445SDouglas Gilbert 		};
1717c65b1445SDouglas Gilbert 
1718c65b1445SDouglas Gilbert         memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1719c65b1445SDouglas Gilbert         return sizeof(temp_l_pg);
1720c65b1445SDouglas Gilbert }
1721c65b1445SDouglas Gilbert 
1722c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr)
1723c65b1445SDouglas Gilbert {
1724c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1725c65b1445SDouglas Gilbert 		};
1726c65b1445SDouglas Gilbert 
1727c65b1445SDouglas Gilbert         memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1728c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
1729c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
1730c65b1445SDouglas Gilbert 		arr[5] = 0xff;
1731c65b1445SDouglas Gilbert 	}
1732c65b1445SDouglas Gilbert         return sizeof(ie_l_pg);
1733c65b1445SDouglas Gilbert }
1734c65b1445SDouglas Gilbert 
1735c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
1736c65b1445SDouglas Gilbert 
1737c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp,
1738c65b1445SDouglas Gilbert                           struct sdebug_dev_info * devip)
1739c65b1445SDouglas Gilbert {
174023183910SDouglas Gilbert 	int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
1741c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
174201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1743c65b1445SDouglas Gilbert 
1744cbf67842SDouglas Gilbert 	errsts = check_readiness(scp, UAS_ONLY, devip);
1745cbf67842SDouglas Gilbert 	if (errsts)
1746c65b1445SDouglas Gilbert 		return errsts;
1747c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1748c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
1749c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
1750c65b1445SDouglas Gilbert 	if (ppc || sp) {
1751cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
1752c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
1753c65b1445SDouglas Gilbert 		return check_condition_result;
1754c65b1445SDouglas Gilbert 	}
1755c65b1445SDouglas Gilbert 	pcontrol = (cmd[2] & 0xc0) >> 6;
1756c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
175723183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
1758c65b1445SDouglas Gilbert 	alloc_len = (cmd[7] << 8) + cmd[8];
1759c65b1445SDouglas Gilbert 	arr[0] = pcode;
176023183910SDouglas Gilbert 	if (0 == subpcode) {
1761c65b1445SDouglas Gilbert 		switch (pcode) {
1762c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
1763c65b1445SDouglas Gilbert 			n = 4;
1764c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
1765c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
1766c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
1767c65b1445SDouglas Gilbert 			arr[3] = n - 4;
1768c65b1445SDouglas Gilbert 			break;
1769c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
1770c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
1771c65b1445SDouglas Gilbert 			break;
1772c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
1773c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
1774c65b1445SDouglas Gilbert 			break;
1775c65b1445SDouglas Gilbert 		default:
1776cbf67842SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
1777c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1778c65b1445SDouglas Gilbert 			return check_condition_result;
1779c65b1445SDouglas Gilbert 		}
178023183910SDouglas Gilbert 	} else if (0xff == subpcode) {
178123183910SDouglas Gilbert 		arr[0] |= 0x40;
178223183910SDouglas Gilbert 		arr[1] = subpcode;
178323183910SDouglas Gilbert 		switch (pcode) {
178423183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
178523183910SDouglas Gilbert 			n = 4;
178623183910SDouglas Gilbert 			arr[n++] = 0x0;
178723183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
178823183910SDouglas Gilbert 			arr[n++] = 0x0;
178923183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
179023183910SDouglas Gilbert 			arr[n++] = 0xd;
179123183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
179223183910SDouglas Gilbert 			arr[n++] = 0x2f;
179323183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
179423183910SDouglas Gilbert 			arr[3] = n - 4;
179523183910SDouglas Gilbert 			break;
179623183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
179723183910SDouglas Gilbert 			n = 4;
179823183910SDouglas Gilbert 			arr[n++] = 0xd;
179923183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
180023183910SDouglas Gilbert 			arr[3] = n - 4;
180123183910SDouglas Gilbert 			break;
180223183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
180323183910SDouglas Gilbert 			n = 4;
180423183910SDouglas Gilbert 			arr[n++] = 0x2f;
180523183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
180623183910SDouglas Gilbert 			arr[3] = n - 4;
180723183910SDouglas Gilbert 			break;
180823183910SDouglas Gilbert 		default:
1809cbf67842SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST,
181023183910SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
181123183910SDouglas Gilbert 			return check_condition_result;
181223183910SDouglas Gilbert 		}
181323183910SDouglas Gilbert 	} else {
1814cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
181523183910SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
181623183910SDouglas Gilbert 		return check_condition_result;
181723183910SDouglas Gilbert 	}
1818c65b1445SDouglas Gilbert 	len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1819c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1820c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
1821c65b1445SDouglas Gilbert }
1822c65b1445SDouglas Gilbert 
1823cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp,
182419789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
18251da177e4SLinus Torvalds {
1826c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
1827cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
18281da177e4SLinus Torvalds 		return check_condition_result;
18291da177e4SLinus Torvalds 	}
1830c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
1831c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
1832cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
1833c65b1445SDouglas Gilbert 		return check_condition_result;
1834c65b1445SDouglas Gilbert 	}
183519789100SFUJITA Tomonori 	return 0;
183619789100SFUJITA Tomonori }
183719789100SFUJITA Tomonori 
1838a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
183919789100SFUJITA Tomonori static int do_device_access(struct scsi_cmnd *scmd,
184019789100SFUJITA Tomonori 			    unsigned long long lba, unsigned int num, int write)
184119789100SFUJITA Tomonori {
184219789100SFUJITA Tomonori 	int ret;
1843a361cc00SDarrick J. Wong 	unsigned long long block, rest = 0;
1844a4517511SAkinobu Mita 	struct scsi_data_buffer *sdb;
1845a4517511SAkinobu Mita 	enum dma_data_direction dir;
1846a4517511SAkinobu Mita 	size_t (*func)(struct scatterlist *, unsigned int, void *, size_t,
1847a4517511SAkinobu Mita 		       off_t);
184819789100SFUJITA Tomonori 
1849a4517511SAkinobu Mita 	if (write) {
1850a4517511SAkinobu Mita 		sdb = scsi_out(scmd);
1851a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
1852a4517511SAkinobu Mita 		func = sg_pcopy_to_buffer;
1853a4517511SAkinobu Mita 	} else {
1854a4517511SAkinobu Mita 		sdb = scsi_in(scmd);
1855a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
1856a4517511SAkinobu Mita 		func = sg_pcopy_from_buffer;
1857a4517511SAkinobu Mita 	}
1858a4517511SAkinobu Mita 
1859a4517511SAkinobu Mita 	if (!sdb->length)
1860a4517511SAkinobu Mita 		return 0;
1861a4517511SAkinobu Mita 	if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
1862a4517511SAkinobu Mita 		return -1;
186319789100SFUJITA Tomonori 
186419789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
186519789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
186619789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
186719789100SFUJITA Tomonori 
1868a4517511SAkinobu Mita 	ret = func(sdb->table.sgl, sdb->table.nents,
1869a4517511SAkinobu Mita 		   fake_storep + (block * scsi_debug_sector_size),
1870a4517511SAkinobu Mita 		   (num - rest) * scsi_debug_sector_size, 0);
1871a4517511SAkinobu Mita 	if (ret != (num - rest) * scsi_debug_sector_size)
1872a4517511SAkinobu Mita 		return ret;
1873a4517511SAkinobu Mita 
1874a4517511SAkinobu Mita 	if (rest) {
1875a4517511SAkinobu Mita 		ret += func(sdb->table.sgl, sdb->table.nents,
1876a4517511SAkinobu Mita 			    fake_storep, rest * scsi_debug_sector_size,
1877597136abSMartin K. Petersen 			    (num - rest) * scsi_debug_sector_size);
1878a4517511SAkinobu Mita 	}
187919789100SFUJITA Tomonori 
188019789100SFUJITA Tomonori 	return ret;
188119789100SFUJITA Tomonori }
188219789100SFUJITA Tomonori 
188351d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
1884beb40ea4SAkinobu Mita {
188551d648afSAkinobu Mita 	__be16 csum;
1886beb40ea4SAkinobu Mita 
188751d648afSAkinobu Mita 	if (scsi_debug_guard)
188851d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
188951d648afSAkinobu Mita 	else
1890beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
189151d648afSAkinobu Mita 
1892beb40ea4SAkinobu Mita 	return csum;
1893beb40ea4SAkinobu Mita }
1894beb40ea4SAkinobu Mita 
1895beb40ea4SAkinobu Mita static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
1896beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
1897beb40ea4SAkinobu Mita {
189851d648afSAkinobu Mita 	__be16 csum = dif_compute_csum(data, scsi_debug_sector_size);
1899beb40ea4SAkinobu Mita 
1900beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
1901beb40ea4SAkinobu Mita 		pr_err("%s: GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
1902beb40ea4SAkinobu Mita 			__func__,
1903beb40ea4SAkinobu Mita 			(unsigned long)sector,
1904beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
1905beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
1906beb40ea4SAkinobu Mita 		return 0x01;
1907beb40ea4SAkinobu Mita 	}
1908beb40ea4SAkinobu Mita 	if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
1909beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
1910beb40ea4SAkinobu Mita 		pr_err("%s: REF check failed on sector %lu\n",
1911beb40ea4SAkinobu Mita 			__func__, (unsigned long)sector);
1912beb40ea4SAkinobu Mita 		return 0x03;
1913beb40ea4SAkinobu Mita 	}
1914beb40ea4SAkinobu Mita 	if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1915beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
1916beb40ea4SAkinobu Mita 		pr_err("%s: REF check failed on sector %lu\n",
1917beb40ea4SAkinobu Mita 			__func__, (unsigned long)sector);
1918beb40ea4SAkinobu Mita 		return 0x03;
1919beb40ea4SAkinobu Mita 	}
1920beb40ea4SAkinobu Mita 	return 0;
1921beb40ea4SAkinobu Mita }
1922beb40ea4SAkinobu Mita 
1923bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
192465f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
1925c6a44287SMartin K. Petersen {
1926be4e11beSAkinobu Mita 	size_t resid;
1927c6a44287SMartin K. Petersen 	void *paddr;
192814faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
1929be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
1930c6a44287SMartin K. Petersen 
1931e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
1932e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
1933c6a44287SMartin K. Petersen 
1934be4e11beSAkinobu Mita 	sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
1935be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
1936be4e11beSAkinobu Mita 			(read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
1937be4e11beSAkinobu Mita 
1938be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
1939be4e11beSAkinobu Mita 		size_t len = min(miter.length, resid);
194014faa944SAkinobu Mita 		void *start = dif_store(sector);
1941be4e11beSAkinobu Mita 		size_t rest = 0;
194214faa944SAkinobu Mita 
194314faa944SAkinobu Mita 		if (dif_store_end < start + len)
194414faa944SAkinobu Mita 			rest = start + len - dif_store_end;
1945c6a44287SMartin K. Petersen 
1946be4e11beSAkinobu Mita 		paddr = miter.addr;
194714faa944SAkinobu Mita 
194865f72f2aSAkinobu Mita 		if (read)
194965f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
195065f72f2aSAkinobu Mita 		else
195165f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
195265f72f2aSAkinobu Mita 
195365f72f2aSAkinobu Mita 		if (rest) {
195465f72f2aSAkinobu Mita 			if (read)
195514faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
195665f72f2aSAkinobu Mita 			else
195765f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
195865f72f2aSAkinobu Mita 		}
1959c6a44287SMartin K. Petersen 
1960e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
1961c6a44287SMartin K. Petersen 		resid -= len;
1962c6a44287SMartin K. Petersen 	}
1963be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
1964bb8c063cSAkinobu Mita }
1965c6a44287SMartin K. Petersen 
1966bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
1967bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
1968bb8c063cSAkinobu Mita {
1969bb8c063cSAkinobu Mita 	unsigned int i;
1970bb8c063cSAkinobu Mita 	struct sd_dif_tuple *sdt;
1971bb8c063cSAkinobu Mita 	sector_t sector;
1972bb8c063cSAkinobu Mita 
1973c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
1974bb8c063cSAkinobu Mita 		int ret;
1975bb8c063cSAkinobu Mita 
1976bb8c063cSAkinobu Mita 		sector = start_sec + i;
1977bb8c063cSAkinobu Mita 		sdt = dif_store(sector);
1978bb8c063cSAkinobu Mita 
197951d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
1980bb8c063cSAkinobu Mita 			continue;
1981bb8c063cSAkinobu Mita 
1982bb8c063cSAkinobu Mita 		ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
1983bb8c063cSAkinobu Mita 		if (ret) {
1984bb8c063cSAkinobu Mita 			dif_errors++;
1985bb8c063cSAkinobu Mita 			return ret;
1986bb8c063cSAkinobu Mita 		}
1987bb8c063cSAkinobu Mita 	}
1988bb8c063cSAkinobu Mita 
198965f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, true);
1990c6a44287SMartin K. Petersen 	dix_reads++;
1991c6a44287SMartin K. Petersen 
1992c6a44287SMartin K. Petersen 	return 0;
1993c6a44287SMartin K. Petersen }
1994c6a44287SMartin K. Petersen 
199519789100SFUJITA Tomonori static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
1996cbf67842SDouglas Gilbert 		     unsigned int num, u32 ei_lba)
199719789100SFUJITA Tomonori {
199819789100SFUJITA Tomonori 	unsigned long iflags;
199919789100SFUJITA Tomonori 	int ret;
200019789100SFUJITA Tomonori 
2001cbf67842SDouglas Gilbert 	ret = check_device_access_params(SCpnt, lba, num);
200219789100SFUJITA Tomonori 	if (ret)
200319789100SFUJITA Tomonori 		return ret;
200419789100SFUJITA Tomonori 
20051da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
200632f7ef73SDouglas Gilbert 	    (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
2007c65b1445SDouglas Gilbert 	    ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
2008c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
2009cbf67842SDouglas Gilbert 		mk_sense_buffer(SCpnt, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
2010c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
2011cbf67842SDouglas Gilbert 		if (0x70 == (SCpnt->sense_buffer[0] & 0x7f)) {
2012cbf67842SDouglas Gilbert 			SCpnt->sense_buffer[0] |= 0x80;	/* Valid bit */
201332f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
201432f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
2015cbf67842SDouglas Gilbert 			SCpnt->sense_buffer[3] = (ret >> 24) & 0xff;
2016cbf67842SDouglas Gilbert 			SCpnt->sense_buffer[4] = (ret >> 16) & 0xff;
2017cbf67842SDouglas Gilbert 			SCpnt->sense_buffer[5] = (ret >> 8) & 0xff;
2018cbf67842SDouglas Gilbert 			SCpnt->sense_buffer[6] = ret & 0xff;
2019c65b1445SDouglas Gilbert 		}
2020a87e3a67SDouglas Gilbert 	        scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
20211da177e4SLinus Torvalds 		return check_condition_result;
20221da177e4SLinus Torvalds 	}
2023c6a44287SMartin K. Petersen 
20246c78cc06SAkinobu Mita 	read_lock_irqsave(&atomic_rw, iflags);
20256c78cc06SAkinobu Mita 
2026c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2027c6a44287SMartin K. Petersen 	if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
2028395cef03SMartin K. Petersen 		int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
2029c6a44287SMartin K. Petersen 
2030c6a44287SMartin K. Petersen 		if (prot_ret) {
20316c78cc06SAkinobu Mita 			read_unlock_irqrestore(&atomic_rw, iflags);
2032cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, ABORTED_COMMAND, 0x10, prot_ret);
2033c6a44287SMartin K. Petersen 			return illegal_condition_result;
2034c6a44287SMartin K. Petersen 		}
2035c6a44287SMartin K. Petersen 	}
2036c6a44287SMartin K. Petersen 
2037cbf67842SDouglas Gilbert 	ret = do_device_access(SCpnt, lba, num, 0);
20381da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
2039a4517511SAkinobu Mita 	if (ret == -1)
2040a4517511SAkinobu Mita 		return DID_ERROR << 16;
2041a4517511SAkinobu Mita 
2042a4517511SAkinobu Mita 	scsi_in(SCpnt)->resid = scsi_bufflen(SCpnt) - ret;
2043a4517511SAkinobu Mita 
2044a4517511SAkinobu Mita 	return 0;
20451da177e4SLinus Torvalds }
20461da177e4SLinus Torvalds 
2047c6a44287SMartin K. Petersen void dump_sector(unsigned char *buf, int len)
2048c6a44287SMartin K. Petersen {
2049cbf67842SDouglas Gilbert 	int i, j, n;
2050c6a44287SMartin K. Petersen 
2051cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
2052c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
2053cbf67842SDouglas Gilbert 		char b[128];
2054c6a44287SMartin K. Petersen 
2055cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
2056c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
2057c6a44287SMartin K. Petersen 
2058cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
2059cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2060cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
2061cbf67842SDouglas Gilbert 			else
2062cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2063cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
2064cbf67842SDouglas Gilbert 		}
2065cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
2066c6a44287SMartin K. Petersen 	}
2067c6a44287SMartin K. Petersen }
2068c6a44287SMartin K. Petersen 
2069c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
2070395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
2071c6a44287SMartin K. Petersen {
2072be4e11beSAkinobu Mita 	int ret;
2073c6a44287SMartin K. Petersen 	struct sd_dif_tuple *sdt;
2074be4e11beSAkinobu Mita 	void *daddr;
207565f72f2aSAkinobu Mita 	sector_t sector = start_sec;
2076c6a44287SMartin K. Petersen 	int ppage_offset;
2077be4e11beSAkinobu Mita 	int dpage_offset;
2078be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
2079be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
2080c6a44287SMartin K. Petersen 
2081c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
2082c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2083c6a44287SMartin K. Petersen 
2084be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2085be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
2086be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2087be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2088be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2089c6a44287SMartin K. Petersen 
2090be4e11beSAkinobu Mita 	/* For each protection page */
2091be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
2092be4e11beSAkinobu Mita 		dpage_offset = 0;
2093be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
2094be4e11beSAkinobu Mita 			ret = 0x01;
2095be4e11beSAkinobu Mita 			goto out;
2096c6a44287SMartin K. Petersen 		}
2097c6a44287SMartin K. Petersen 
2098be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
2099be4e11beSAkinobu Mita 		     ppage_offset += sizeof(struct sd_dif_tuple)) {
2100be4e11beSAkinobu Mita 			/* If we're at the end of the current
2101be4e11beSAkinobu Mita 			 * data page advance to the next one
2102be4e11beSAkinobu Mita 			 */
2103be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
2104be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
2105be4e11beSAkinobu Mita 					ret = 0x01;
2106be4e11beSAkinobu Mita 					goto out;
2107be4e11beSAkinobu Mita 				}
2108be4e11beSAkinobu Mita 				dpage_offset = 0;
2109be4e11beSAkinobu Mita 			}
2110c6a44287SMartin K. Petersen 
2111be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
2112be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
2113be4e11beSAkinobu Mita 
2114be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
2115beb40ea4SAkinobu Mita 			if (ret) {
2116be4e11beSAkinobu Mita 				dump_sector(daddr, scsi_debug_sector_size);
2117395cef03SMartin K. Petersen 				goto out;
2118395cef03SMartin K. Petersen 			}
2119395cef03SMartin K. Petersen 
2120c6a44287SMartin K. Petersen 			sector++;
2121395cef03SMartin K. Petersen 			ei_lba++;
2122be4e11beSAkinobu Mita 			dpage_offset += scsi_debug_sector_size;
2123c6a44287SMartin K. Petersen 		}
2124be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
2125be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
2126c6a44287SMartin K. Petersen 	}
2127be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2128c6a44287SMartin K. Petersen 
212965f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
2130c6a44287SMartin K. Petersen 	dix_writes++;
2131c6a44287SMartin K. Petersen 
2132c6a44287SMartin K. Petersen 	return 0;
2133c6a44287SMartin K. Petersen 
2134c6a44287SMartin K. Petersen out:
2135c6a44287SMartin K. Petersen 	dif_errors++;
2136be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
2137be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2138c6a44287SMartin K. Petersen 	return ret;
2139c6a44287SMartin K. Petersen }
2140c6a44287SMartin K. Petersen 
2141b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
2142b90ebc3dSAkinobu Mita {
2143b90ebc3dSAkinobu Mita 	if (scsi_debug_unmap_alignment) {
2144b90ebc3dSAkinobu Mita 		lba += scsi_debug_unmap_granularity -
2145b90ebc3dSAkinobu Mita 			scsi_debug_unmap_alignment;
2146b90ebc3dSAkinobu Mita 	}
2147b90ebc3dSAkinobu Mita 	do_div(lba, scsi_debug_unmap_granularity);
2148b90ebc3dSAkinobu Mita 
2149b90ebc3dSAkinobu Mita 	return lba;
2150b90ebc3dSAkinobu Mita }
2151b90ebc3dSAkinobu Mita 
2152b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
2153b90ebc3dSAkinobu Mita {
2154a027b5b9SAkinobu Mita 	sector_t lba = index * scsi_debug_unmap_granularity;
2155a027b5b9SAkinobu Mita 
2156a027b5b9SAkinobu Mita 	if (scsi_debug_unmap_alignment) {
2157a027b5b9SAkinobu Mita 		lba -= scsi_debug_unmap_granularity -
2158b90ebc3dSAkinobu Mita 			scsi_debug_unmap_alignment;
2159b90ebc3dSAkinobu Mita 	}
2160b90ebc3dSAkinobu Mita 
2161a027b5b9SAkinobu Mita 	return lba;
2162a027b5b9SAkinobu Mita }
2163a027b5b9SAkinobu Mita 
216444d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
216544d92694SMartin K. Petersen {
2166b90ebc3dSAkinobu Mita 	sector_t end;
2167b90ebc3dSAkinobu Mita 	unsigned int mapped;
2168b90ebc3dSAkinobu Mita 	unsigned long index;
2169b90ebc3dSAkinobu Mita 	unsigned long next;
217044d92694SMartin K. Petersen 
2171b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
2172b90ebc3dSAkinobu Mita 	mapped = test_bit(index, map_storep);
217344d92694SMartin K. Petersen 
217444d92694SMartin K. Petersen 	if (mapped)
2175b90ebc3dSAkinobu Mita 		next = find_next_zero_bit(map_storep, map_size, index);
217644d92694SMartin K. Petersen 	else
2177b90ebc3dSAkinobu Mita 		next = find_next_bit(map_storep, map_size, index);
217844d92694SMartin K. Petersen 
2179b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
218044d92694SMartin K. Petersen 	*num = end - lba;
218144d92694SMartin K. Petersen 
218244d92694SMartin K. Petersen 	return mapped;
218344d92694SMartin K. Petersen }
218444d92694SMartin K. Petersen 
218544d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
218644d92694SMartin K. Petersen {
218744d92694SMartin K. Petersen 	sector_t end = lba + len;
218844d92694SMartin K. Petersen 
218944d92694SMartin K. Petersen 	while (lba < end) {
2190b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
219144d92694SMartin K. Petersen 
2192b90ebc3dSAkinobu Mita 		if (index < map_size)
2193b90ebc3dSAkinobu Mita 			set_bit(index, map_storep);
219444d92694SMartin K. Petersen 
2195b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
219644d92694SMartin K. Petersen 	}
219744d92694SMartin K. Petersen }
219844d92694SMartin K. Petersen 
219944d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
220044d92694SMartin K. Petersen {
220144d92694SMartin K. Petersen 	sector_t end = lba + len;
220244d92694SMartin K. Petersen 
220344d92694SMartin K. Petersen 	while (lba < end) {
2204b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
220544d92694SMartin K. Petersen 
2206b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
2207b90ebc3dSAkinobu Mita 		    lba + scsi_debug_unmap_granularity <= end &&
2208b90ebc3dSAkinobu Mita 		    index < map_size) {
2209b90ebc3dSAkinobu Mita 			clear_bit(index, map_storep);
2210b90ebc3dSAkinobu Mita 			if (scsi_debug_lbprz) {
2211be1dd78dSEric Sandeen 				memset(fake_storep +
2212cc34a8e6SAkinobu Mita 				       lba * scsi_debug_sector_size, 0,
2213cc34a8e6SAkinobu Mita 				       scsi_debug_sector_size *
2214cc34a8e6SAkinobu Mita 				       scsi_debug_unmap_granularity);
2215be1dd78dSEric Sandeen 			}
2216e9926b43SAkinobu Mita 			if (dif_storep) {
2217e9926b43SAkinobu Mita 				memset(dif_storep + lba, 0xff,
2218e9926b43SAkinobu Mita 				       sizeof(*dif_storep) *
2219e9926b43SAkinobu Mita 				       scsi_debug_unmap_granularity);
2220e9926b43SAkinobu Mita 			}
2221b90ebc3dSAkinobu Mita 		}
2222b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
222344d92694SMartin K. Petersen 	}
222444d92694SMartin K. Petersen }
222544d92694SMartin K. Petersen 
2226c65b1445SDouglas Gilbert static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
2227cbf67842SDouglas Gilbert 		      unsigned int num, u32 ei_lba)
22281da177e4SLinus Torvalds {
22291da177e4SLinus Torvalds 	unsigned long iflags;
223019789100SFUJITA Tomonori 	int ret;
22311da177e4SLinus Torvalds 
2232cbf67842SDouglas Gilbert 	ret = check_device_access_params(SCpnt, lba, num);
223319789100SFUJITA Tomonori 	if (ret)
223419789100SFUJITA Tomonori 		return ret;
22351da177e4SLinus Torvalds 
22366c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
22376c78cc06SAkinobu Mita 
2238c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2239c6a44287SMartin K. Petersen 	if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
2240395cef03SMartin K. Petersen 		int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
2241c6a44287SMartin K. Petersen 
2242c6a44287SMartin K. Petersen 		if (prot_ret) {
22436c78cc06SAkinobu Mita 			write_unlock_irqrestore(&atomic_rw, iflags);
2244cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, ILLEGAL_REQUEST, 0x10,
2245cbf67842SDouglas Gilbert 					prot_ret);
2246c6a44287SMartin K. Petersen 			return illegal_condition_result;
2247c6a44287SMartin K. Petersen 		}
2248c6a44287SMartin K. Petersen 	}
2249c6a44287SMartin K. Petersen 
2250cbf67842SDouglas Gilbert 	ret = do_device_access(SCpnt, lba, num, 1);
22519ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
225244d92694SMartin K. Petersen 		map_region(lba, num);
22531da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
225419789100SFUJITA Tomonori 	if (-1 == ret)
22551da177e4SLinus Torvalds 		return (DID_ERROR << 16);
2256597136abSMartin K. Petersen 	else if ((ret < (num * scsi_debug_sector_size)) &&
22571da177e4SLinus Torvalds 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
2258cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
2259cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
2260cbf67842SDouglas Gilbert 			    my_name, num * scsi_debug_sector_size, ret);
226144d92694SMartin K. Petersen 
22621da177e4SLinus Torvalds 	return 0;
22631da177e4SLinus Torvalds }
22641da177e4SLinus Torvalds 
226544d92694SMartin K. Petersen static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,
2266cbf67842SDouglas Gilbert 		      unsigned int num, u32 ei_lba, unsigned int unmap)
226744d92694SMartin K. Petersen {
226844d92694SMartin K. Petersen 	unsigned long iflags;
226944d92694SMartin K. Petersen 	unsigned long long i;
227044d92694SMartin K. Petersen 	int ret;
227144d92694SMartin K. Petersen 
2272cbf67842SDouglas Gilbert 	ret = check_device_access_params(scmd, lba, num);
227344d92694SMartin K. Petersen 	if (ret)
227444d92694SMartin K. Petersen 		return ret;
227544d92694SMartin K. Petersen 
22765b94e232SMartin K. Petersen 	if (num > scsi_debug_write_same_length) {
2277cbf67842SDouglas Gilbert 		mk_sense_buffer(scmd, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
22785b94e232SMartin K. Petersen 				0);
22795b94e232SMartin K. Petersen 		return check_condition_result;
22805b94e232SMartin K. Petersen 	}
22815b94e232SMartin K. Petersen 
228244d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
228344d92694SMartin K. Petersen 
22849ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
228544d92694SMartin K. Petersen 		unmap_region(lba, num);
228644d92694SMartin K. Petersen 		goto out;
228744d92694SMartin K. Petersen 	}
228844d92694SMartin K. Petersen 
228944d92694SMartin K. Petersen 	/* Else fetch one logical block */
229044d92694SMartin K. Petersen 	ret = fetch_to_dev_buffer(scmd,
229144d92694SMartin K. Petersen 				  fake_storep + (lba * scsi_debug_sector_size),
229244d92694SMartin K. Petersen 				  scsi_debug_sector_size);
229344d92694SMartin K. Petersen 
229444d92694SMartin K. Petersen 	if (-1 == ret) {
229544d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
229644d92694SMartin K. Petersen 		return (DID_ERROR << 16);
229744d92694SMartin K. Petersen 	} else if ((ret < (num * scsi_debug_sector_size)) &&
229844d92694SMartin K. Petersen 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
2299cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scmd->device,
2300cbf67842SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
2301cbf67842SDouglas Gilbert 			    my_name, "write same",
2302cbf67842SDouglas Gilbert 			    num * scsi_debug_sector_size, ret);
230344d92694SMartin K. Petersen 
230444d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
230544d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
230644d92694SMartin K. Petersen 		memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size),
230744d92694SMartin K. Petersen 		       fake_storep + (lba * scsi_debug_sector_size),
230844d92694SMartin K. Petersen 		       scsi_debug_sector_size);
230944d92694SMartin K. Petersen 
23109ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
231144d92694SMartin K. Petersen 		map_region(lba, num);
231244d92694SMartin K. Petersen out:
231344d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
231444d92694SMartin K. Petersen 
231544d92694SMartin K. Petersen 	return 0;
231644d92694SMartin K. Petersen }
231744d92694SMartin K. Petersen 
231844d92694SMartin K. Petersen struct unmap_block_desc {
231944d92694SMartin K. Petersen 	__be64	lba;
232044d92694SMartin K. Petersen 	__be32	blocks;
232144d92694SMartin K. Petersen 	__be32	__reserved;
232244d92694SMartin K. Petersen };
232344d92694SMartin K. Petersen 
232444d92694SMartin K. Petersen static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
232544d92694SMartin K. Petersen {
232644d92694SMartin K. Petersen 	unsigned char *buf;
232744d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
232844d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
232944d92694SMartin K. Petersen 	int ret;
23306c78cc06SAkinobu Mita 	unsigned long iflags;
233144d92694SMartin K. Petersen 
2332cbf67842SDouglas Gilbert 	ret = check_readiness(scmd, UAS_ONLY, devip);
233344d92694SMartin K. Petersen 	if (ret)
233444d92694SMartin K. Petersen 		return ret;
233544d92694SMartin K. Petersen 
233644d92694SMartin K. Petersen 	payload_len = get_unaligned_be16(&scmd->cmnd[7]);
233744d92694SMartin K. Petersen 	BUG_ON(scsi_bufflen(scmd) != payload_len);
233844d92694SMartin K. Petersen 
233944d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
234044d92694SMartin K. Petersen 
234144d92694SMartin K. Petersen 	buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC);
234244d92694SMartin K. Petersen 	if (!buf)
234344d92694SMartin K. Petersen 		return check_condition_result;
234444d92694SMartin K. Petersen 
234544d92694SMartin K. Petersen 	scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
234644d92694SMartin K. Petersen 
234744d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
234844d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
234944d92694SMartin K. Petersen 
235044d92694SMartin K. Petersen 	desc = (void *)&buf[8];
235144d92694SMartin K. Petersen 
23526c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
23536c78cc06SAkinobu Mita 
235444d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
235544d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
235644d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
235744d92694SMartin K. Petersen 
2358cbf67842SDouglas Gilbert 		ret = check_device_access_params(scmd, lba, num);
235944d92694SMartin K. Petersen 		if (ret)
236044d92694SMartin K. Petersen 			goto out;
236144d92694SMartin K. Petersen 
236244d92694SMartin K. Petersen 		unmap_region(lba, num);
236344d92694SMartin K. Petersen 	}
236444d92694SMartin K. Petersen 
236544d92694SMartin K. Petersen 	ret = 0;
236644d92694SMartin K. Petersen 
236744d92694SMartin K. Petersen out:
23686c78cc06SAkinobu Mita 	write_unlock_irqrestore(&atomic_rw, iflags);
236944d92694SMartin K. Petersen 	kfree(buf);
237044d92694SMartin K. Petersen 
237144d92694SMartin K. Petersen 	return ret;
237244d92694SMartin K. Petersen }
237344d92694SMartin K. Petersen 
237444d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
237544d92694SMartin K. Petersen 
237644d92694SMartin K. Petersen static int resp_get_lba_status(struct scsi_cmnd * scmd,
237744d92694SMartin K. Petersen 			       struct sdebug_dev_info * devip)
237844d92694SMartin K. Petersen {
237944d92694SMartin K. Petersen 	unsigned long long lba;
238044d92694SMartin K. Petersen 	unsigned int alloc_len, mapped, num;
238144d92694SMartin K. Petersen 	unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN];
238244d92694SMartin K. Petersen 	int ret;
238344d92694SMartin K. Petersen 
2384cbf67842SDouglas Gilbert 	ret = check_readiness(scmd, UAS_ONLY, devip);
238544d92694SMartin K. Petersen 	if (ret)
238644d92694SMartin K. Petersen 		return ret;
238744d92694SMartin K. Petersen 
238844d92694SMartin K. Petersen 	lba = get_unaligned_be64(&scmd->cmnd[2]);
238944d92694SMartin K. Petersen 	alloc_len = get_unaligned_be32(&scmd->cmnd[10]);
239044d92694SMartin K. Petersen 
239144d92694SMartin K. Petersen 	if (alloc_len < 24)
239244d92694SMartin K. Petersen 		return 0;
239344d92694SMartin K. Petersen 
2394cbf67842SDouglas Gilbert 	ret = check_device_access_params(scmd, lba, 1);
239544d92694SMartin K. Petersen 	if (ret)
239644d92694SMartin K. Petersen 		return ret;
239744d92694SMartin K. Petersen 
239844d92694SMartin K. Petersen 	mapped = map_state(lba, &num);
239944d92694SMartin K. Petersen 
240044d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
2401de13e965SDouglas Gilbert 	put_unaligned_be32(20, &arr[0]);	/* Parameter Data Length */
240244d92694SMartin K. Petersen 	put_unaligned_be64(lba, &arr[8]);	/* LBA */
240344d92694SMartin K. Petersen 	put_unaligned_be32(num, &arr[16]);	/* Number of blocks */
240444d92694SMartin K. Petersen 	arr[20] = !mapped;			/* mapped = 0, unmapped = 1 */
240544d92694SMartin K. Petersen 
240644d92694SMartin K. Petersen 	return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN);
240744d92694SMartin K. Petersen }
240844d92694SMartin K. Petersen 
2409c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256
24101da177e4SLinus Torvalds 
24111da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp,
24121da177e4SLinus Torvalds 			    struct sdebug_dev_info * devip)
24131da177e4SLinus Torvalds {
24141da177e4SLinus Torvalds 	unsigned int alloc_len;
24159cb78c16SHannes Reinecke 	int lun_cnt, i, upper, num, n;
24169cb78c16SHannes Reinecke 	u64 wlun, lun;
241701123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
24181da177e4SLinus Torvalds 	int select_report = (int)cmd[2];
24191da177e4SLinus Torvalds 	struct scsi_lun *one_lun;
24201da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_RLUN_ARR_SZ];
2421c65b1445SDouglas Gilbert 	unsigned char * max_addr;
24221da177e4SLinus Torvalds 
24231da177e4SLinus Torvalds 	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
2424c65b1445SDouglas Gilbert 	if ((alloc_len < 4) || (select_report > 2)) {
2425cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
24261da177e4SLinus Torvalds 			       	0);
24271da177e4SLinus Torvalds 		return check_condition_result;
24281da177e4SLinus Torvalds 	}
24291da177e4SLinus Torvalds 	/* can produce response with up to 16k luns (lun 0 to lun 16383) */
24301da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
24311da177e4SLinus Torvalds 	lun_cnt = scsi_debug_max_luns;
2432c65b1445SDouglas Gilbert 	if (1 == select_report)
2433c65b1445SDouglas Gilbert 		lun_cnt = 0;
2434c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
2435c65b1445SDouglas Gilbert 		--lun_cnt;
2436c65b1445SDouglas Gilbert 	wlun = (select_report > 0) ? 1 : 0;
2437c65b1445SDouglas Gilbert 	num = lun_cnt + wlun;
2438c65b1445SDouglas Gilbert 	arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
2439c65b1445SDouglas Gilbert 	arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
2440c65b1445SDouglas Gilbert 	n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
2441c65b1445SDouglas Gilbert 			    sizeof(struct scsi_lun)), num);
2442c65b1445SDouglas Gilbert 	if (n < num) {
2443c65b1445SDouglas Gilbert 		wlun = 0;
2444c65b1445SDouglas Gilbert 		lun_cnt = n;
2445c65b1445SDouglas Gilbert 	}
24461da177e4SLinus Torvalds 	one_lun = (struct scsi_lun *) &arr[8];
2447c65b1445SDouglas Gilbert 	max_addr = arr + SDEBUG_RLUN_ARR_SZ;
2448c65b1445SDouglas Gilbert 	for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
2449c65b1445SDouglas Gilbert              ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
2450c65b1445SDouglas Gilbert 	     i++, lun++) {
2451c65b1445SDouglas Gilbert 		upper = (lun >> 8) & 0x3f;
24521da177e4SLinus Torvalds 		if (upper)
24531da177e4SLinus Torvalds 			one_lun[i].scsi_lun[0] =
24541da177e4SLinus Torvalds 			    (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
2455c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = lun & 0xff;
24561da177e4SLinus Torvalds 	}
2457c65b1445SDouglas Gilbert 	if (wlun) {
2458c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
2459c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
2460c65b1445SDouglas Gilbert 		i++;
2461c65b1445SDouglas Gilbert 	}
2462c65b1445SDouglas Gilbert 	alloc_len = (unsigned char *)(one_lun + i) - arr;
24631da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr,
24641da177e4SLinus Torvalds 				    min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
24651da177e4SLinus Torvalds }
24661da177e4SLinus Torvalds 
2467c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
2468c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
2469c639d14eSFUJITA Tomonori {
2470be4e11beSAkinobu Mita 	int j;
2471c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
2472c639d14eSFUJITA Tomonori 	unsigned int offset;
2473c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
2474be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
2475c639d14eSFUJITA Tomonori 
2476c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
2477c639d14eSFUJITA Tomonori 	buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
2478c5af0db9SAkinobu Mita 	if (!buf) {
2479cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY,
2480c5af0db9SAkinobu Mita 				LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
2481c5af0db9SAkinobu Mita 		return check_condition_result;
2482c5af0db9SAkinobu Mita 	}
2483c639d14eSFUJITA Tomonori 
248421a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
2485c639d14eSFUJITA Tomonori 
2486c639d14eSFUJITA Tomonori 	offset = 0;
2487be4e11beSAkinobu Mita 	sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
2488be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_TO_SG);
2489c639d14eSFUJITA Tomonori 
2490be4e11beSAkinobu Mita 	while (sg_miter_next(&miter)) {
2491be4e11beSAkinobu Mita 		kaddr = miter.addr;
2492be4e11beSAkinobu Mita 		for (j = 0; j < miter.length; j++)
2493be4e11beSAkinobu Mita 			*(kaddr + j) ^= *(buf + offset + j);
2494c639d14eSFUJITA Tomonori 
2495be4e11beSAkinobu Mita 		offset += miter.length;
2496c639d14eSFUJITA Tomonori 	}
2497be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
2498c639d14eSFUJITA Tomonori 	kfree(buf);
2499c639d14eSFUJITA Tomonori 
2500be4e11beSAkinobu Mita 	return 0;
2501c639d14eSFUJITA Tomonori }
2502c639d14eSFUJITA Tomonori 
2503cbf67842SDouglas Gilbert /* When timer or tasklet goes off this function is called. */
2504cbf67842SDouglas Gilbert static void sdebug_q_cmd_complete(unsigned long indx)
25051da177e4SLinus Torvalds {
2506cbf67842SDouglas Gilbert 	int qa_indx;
2507cbf67842SDouglas Gilbert 	int retiring = 0;
25081da177e4SLinus Torvalds 	unsigned long iflags;
2509cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
2510cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
2511cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
25121da177e4SLinus Torvalds 
2513cbf67842SDouglas Gilbert 	atomic_inc(&sdebug_completions);
2514cbf67842SDouglas Gilbert 	qa_indx = indx;
2515cbf67842SDouglas Gilbert 	if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
2516cbf67842SDouglas Gilbert 		pr_err("%s: wild qa_indx=%d\n", __func__, qa_indx);
25171da177e4SLinus Torvalds 		return;
25181da177e4SLinus Torvalds 	}
25191da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
2520cbf67842SDouglas Gilbert 	sqcp = &queued_arr[qa_indx];
2521cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
2522cbf67842SDouglas Gilbert 	if (NULL == scp) {
25231da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
2524cbf67842SDouglas Gilbert 		pr_err("%s: scp is NULL\n", __func__);
25251da177e4SLinus Torvalds 		return;
25261da177e4SLinus Torvalds 	}
2527cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
2528cbf67842SDouglas Gilbert 	if (devip)
2529cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
2530cbf67842SDouglas Gilbert 	else
2531cbf67842SDouglas Gilbert 		pr_err("%s: devip=NULL\n", __func__);
2532cbf67842SDouglas Gilbert 	if (atomic_read(&retired_max_queue) > 0)
2533cbf67842SDouglas Gilbert 		retiring = 1;
2534cbf67842SDouglas Gilbert 
2535cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
2536cbf67842SDouglas Gilbert 	if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
25371da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
2538cbf67842SDouglas Gilbert 		pr_err("%s: Unexpected completion\n", __func__);
2539cbf67842SDouglas Gilbert 		return;
25401da177e4SLinus Torvalds 	}
25411da177e4SLinus Torvalds 
2542cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
2543cbf67842SDouglas Gilbert 		int k, retval;
2544cbf67842SDouglas Gilbert 
2545cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
2546cbf67842SDouglas Gilbert 		if (qa_indx >= retval) {
2547cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
2548cbf67842SDouglas Gilbert 			pr_err("%s: index %d too large\n", __func__, retval);
2549cbf67842SDouglas Gilbert 			return;
2550cbf67842SDouglas Gilbert 		}
2551cbf67842SDouglas Gilbert 		k = find_last_bit(queued_in_use_bm, retval);
2552cbf67842SDouglas Gilbert 		if ((k < scsi_debug_max_queue) || (k == retval))
2553cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
2554cbf67842SDouglas Gilbert 		else
2555cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
2556cbf67842SDouglas Gilbert 	}
2557cbf67842SDouglas Gilbert 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
2558cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
2559cbf67842SDouglas Gilbert }
2560cbf67842SDouglas Gilbert 
2561cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
2562cbf67842SDouglas Gilbert static enum hrtimer_restart
2563cbf67842SDouglas Gilbert sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
2564cbf67842SDouglas Gilbert {
2565cbf67842SDouglas Gilbert 	int qa_indx;
2566cbf67842SDouglas Gilbert 	int retiring = 0;
2567cbf67842SDouglas Gilbert 	unsigned long iflags;
2568cbf67842SDouglas Gilbert 	struct sdebug_hrtimer *sd_hrtp = (struct sdebug_hrtimer *)timer;
2569cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
2570cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
2571cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
2572cbf67842SDouglas Gilbert 
2573cbf67842SDouglas Gilbert 	atomic_inc(&sdebug_completions);
2574cbf67842SDouglas Gilbert 	qa_indx = sd_hrtp->qa_indx;
2575cbf67842SDouglas Gilbert 	if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
2576cbf67842SDouglas Gilbert 		pr_err("%s: wild qa_indx=%d\n", __func__, qa_indx);
2577cbf67842SDouglas Gilbert 		goto the_end;
2578cbf67842SDouglas Gilbert 	}
2579cbf67842SDouglas Gilbert 	spin_lock_irqsave(&queued_arr_lock, iflags);
2580cbf67842SDouglas Gilbert 	sqcp = &queued_arr[qa_indx];
2581cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
2582cbf67842SDouglas Gilbert 	if (NULL == scp) {
2583cbf67842SDouglas Gilbert 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
2584cbf67842SDouglas Gilbert 		pr_err("%s: scp is NULL\n", __func__);
2585cbf67842SDouglas Gilbert 		goto the_end;
2586cbf67842SDouglas Gilbert 	}
2587cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
2588cbf67842SDouglas Gilbert 	if (devip)
2589cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
2590cbf67842SDouglas Gilbert 	else
2591cbf67842SDouglas Gilbert 		pr_err("%s: devip=NULL\n", __func__);
2592cbf67842SDouglas Gilbert 	if (atomic_read(&retired_max_queue) > 0)
2593cbf67842SDouglas Gilbert 		retiring = 1;
2594cbf67842SDouglas Gilbert 
2595cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
2596cbf67842SDouglas Gilbert 	if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
2597cbf67842SDouglas Gilbert 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
2598cbf67842SDouglas Gilbert 		pr_err("%s: Unexpected completion\n", __func__);
2599cbf67842SDouglas Gilbert 		goto the_end;
2600cbf67842SDouglas Gilbert 	}
2601cbf67842SDouglas Gilbert 
2602cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
2603cbf67842SDouglas Gilbert 		int k, retval;
2604cbf67842SDouglas Gilbert 
2605cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
2606cbf67842SDouglas Gilbert 		if (qa_indx >= retval) {
2607cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
2608cbf67842SDouglas Gilbert 			pr_err("%s: index %d too large\n", __func__, retval);
2609cbf67842SDouglas Gilbert 			goto the_end;
2610cbf67842SDouglas Gilbert 		}
2611cbf67842SDouglas Gilbert 		k = find_last_bit(queued_in_use_bm, retval);
2612cbf67842SDouglas Gilbert 		if ((k < scsi_debug_max_queue) || (k == retval))
2613cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
2614cbf67842SDouglas Gilbert 		else
2615cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
2616cbf67842SDouglas Gilbert 	}
2617cbf67842SDouglas Gilbert 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
2618cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
2619cbf67842SDouglas Gilbert the_end:
2620cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
2621cbf67842SDouglas Gilbert }
26221da177e4SLinus Torvalds 
26238dea0d02SFUJITA Tomonori static struct sdebug_dev_info *
26248dea0d02SFUJITA Tomonori sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
26255cb2fc06SFUJITA Tomonori {
26265cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
26275cb2fc06SFUJITA Tomonori 
26285cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
26295cb2fc06SFUJITA Tomonori 	if (devip) {
26305cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
26315cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
26325cb2fc06SFUJITA Tomonori 	}
26335cb2fc06SFUJITA Tomonori 	return devip;
26345cb2fc06SFUJITA Tomonori }
26355cb2fc06SFUJITA Tomonori 
26361da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
26371da177e4SLinus Torvalds {
26381da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
26391da177e4SLinus Torvalds 	struct sdebug_dev_info * open_devip = NULL;
26401da177e4SLinus Torvalds 	struct sdebug_dev_info * devip =
26411da177e4SLinus Torvalds 			(struct sdebug_dev_info *)sdev->hostdata;
26421da177e4SLinus Torvalds 
26431da177e4SLinus Torvalds 	if (devip)
26441da177e4SLinus Torvalds 		return devip;
2645d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
26461da177e4SLinus Torvalds 	if (!sdbg_host) {
2647cbf67842SDouglas Gilbert 		pr_err("%s: Host info NULL\n", __func__);
26481da177e4SLinus Torvalds 		return NULL;
26491da177e4SLinus Torvalds         }
26501da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
26511da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
26521da177e4SLinus Torvalds                     (devip->target == sdev->id) &&
26531da177e4SLinus Torvalds                     (devip->lun == sdev->lun))
26541da177e4SLinus Torvalds                         return devip;
26551da177e4SLinus Torvalds 		else {
26561da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
26571da177e4SLinus Torvalds 				open_devip = devip;
26581da177e4SLinus Torvalds 		}
26591da177e4SLinus Torvalds 	}
26605cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
26615cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
26625cb2fc06SFUJITA Tomonori 		if (!open_devip) {
26631da177e4SLinus Torvalds 			printk(KERN_ERR "%s: out of memory at line %d\n",
2664cadbd4a5SHarvey Harrison 				__func__, __LINE__);
26651da177e4SLinus Torvalds 			return NULL;
26661da177e4SLinus Torvalds 		}
26671da177e4SLinus Torvalds 	}
2668a75869d1SFUJITA Tomonori 
26691da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
26701da177e4SLinus Torvalds 	open_devip->target = sdev->id;
26711da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
26721da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
2673cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
2674cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
26751da177e4SLinus Torvalds 	open_devip->used = 1;
2676c65b1445SDouglas Gilbert 	if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2677c65b1445SDouglas Gilbert 		open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
2678a75869d1SFUJITA Tomonori 
26791da177e4SLinus Torvalds 	return open_devip;
26801da177e4SLinus Torvalds }
26811da177e4SLinus Torvalds 
26828dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
26831da177e4SLinus Torvalds {
26848dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
26859cb78c16SHannes Reinecke 		printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %llu>\n",
26868dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
268775ad23bcSNick Piggin 	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
26888dea0d02SFUJITA Tomonori 	return 0;
26898dea0d02SFUJITA Tomonori }
26901da177e4SLinus Torvalds 
26918dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
26928dea0d02SFUJITA Tomonori {
26938dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip;
2694a34c4e98SFUJITA Tomonori 
26951da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
26969cb78c16SHannes Reinecke 		printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %llu>\n",
26978dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
26988dea0d02SFUJITA Tomonori 	if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
26998dea0d02SFUJITA Tomonori 		sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
27008dea0d02SFUJITA Tomonori 	devip = devInfoReg(sdp);
27018dea0d02SFUJITA Tomonori 	if (NULL == devip)
27028dea0d02SFUJITA Tomonori 		return 1;	/* no resources, will be marked offline */
2703c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
27046bb5e6e7SAkinobu Mita 	blk_queue_max_segment_size(sdp->request_queue, -1U);
270578d4e5a0SDouglas Gilbert 	if (scsi_debug_no_uld)
270678d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
27078dea0d02SFUJITA Tomonori 	return 0;
27088dea0d02SFUJITA Tomonori }
27098dea0d02SFUJITA Tomonori 
27108dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
27118dea0d02SFUJITA Tomonori {
27128dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
27138dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
27148dea0d02SFUJITA Tomonori 
27158dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
27169cb78c16SHannes Reinecke 		printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %llu>\n",
27178dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
27188dea0d02SFUJITA Tomonori 	if (devip) {
271925985edcSLucas De Marchi 		/* make this slot available for re-use */
27208dea0d02SFUJITA Tomonori 		devip->used = 0;
27218dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
27228dea0d02SFUJITA Tomonori 	}
27238dea0d02SFUJITA Tomonori }
27248dea0d02SFUJITA Tomonori 
2725cbf67842SDouglas Gilbert /* Returns 1 if cmnd found (deletes its timer or tasklet), else returns 0 */
27268dea0d02SFUJITA Tomonori static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
27278dea0d02SFUJITA Tomonori {
27288dea0d02SFUJITA Tomonori 	unsigned long iflags;
2729cbf67842SDouglas Gilbert 	int k, qmax, r_qmax;
27308dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
2731cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
27328dea0d02SFUJITA Tomonori 
27338dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
2734cbf67842SDouglas Gilbert 	qmax = scsi_debug_max_queue;
2735cbf67842SDouglas Gilbert 	r_qmax = atomic_read(&retired_max_queue);
2736cbf67842SDouglas Gilbert 	if (r_qmax > qmax)
2737cbf67842SDouglas Gilbert 		qmax = r_qmax;
2738cbf67842SDouglas Gilbert 	for (k = 0; k < qmax; ++k) {
2739cbf67842SDouglas Gilbert 		if (test_bit(k, queued_in_use_bm)) {
27408dea0d02SFUJITA Tomonori 			sqcp = &queued_arr[k];
2741cbf67842SDouglas Gilbert 			if (cmnd == sqcp->a_cmnd) {
2742db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
2743db525fceSDouglas Gilbert 					cmnd->device->hostdata;
2744db525fceSDouglas Gilbert 				if (devip)
2745db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
2746db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
2747db525fceSDouglas Gilbert 				spin_unlock_irqrestore(&queued_arr_lock,
2748db525fceSDouglas Gilbert 						       iflags);
2749cbf67842SDouglas Gilbert 				if (scsi_debug_ndelay > 0) {
2750cbf67842SDouglas Gilbert 					if (sqcp->sd_hrtp)
2751cbf67842SDouglas Gilbert 						hrtimer_cancel(
2752cbf67842SDouglas Gilbert 							&sqcp->sd_hrtp->hrt);
2753cbf67842SDouglas Gilbert 				} else if (scsi_debug_delay > 0) {
2754cbf67842SDouglas Gilbert 					if (sqcp->cmnd_timerp)
2755cbf67842SDouglas Gilbert 						del_timer_sync(
2756cbf67842SDouglas Gilbert 							sqcp->cmnd_timerp);
2757cbf67842SDouglas Gilbert 				} else if (scsi_debug_delay < 0) {
2758cbf67842SDouglas Gilbert 					if (sqcp->tletp)
2759cbf67842SDouglas Gilbert 						tasklet_kill(sqcp->tletp);
2760cbf67842SDouglas Gilbert 				}
2761db525fceSDouglas Gilbert 				clear_bit(k, queued_in_use_bm);
2762db525fceSDouglas Gilbert 				return 1;
27638dea0d02SFUJITA Tomonori 			}
27648dea0d02SFUJITA Tomonori 		}
2765cbf67842SDouglas Gilbert 	}
27668dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
2767db525fceSDouglas Gilbert 	return 0;
27688dea0d02SFUJITA Tomonori }
27698dea0d02SFUJITA Tomonori 
2770cbf67842SDouglas Gilbert /* Deletes (stops) timers or tasklets of all queued commands */
27718dea0d02SFUJITA Tomonori static void stop_all_queued(void)
27728dea0d02SFUJITA Tomonori {
27738dea0d02SFUJITA Tomonori 	unsigned long iflags;
27748dea0d02SFUJITA Tomonori 	int k;
27758dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
2776cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
27778dea0d02SFUJITA Tomonori 
27788dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
2779cbf67842SDouglas Gilbert 	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2780cbf67842SDouglas Gilbert 		if (test_bit(k, queued_in_use_bm)) {
27818dea0d02SFUJITA Tomonori 			sqcp = &queued_arr[k];
2782cbf67842SDouglas Gilbert 			if (sqcp->a_cmnd) {
2783db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
2784db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
2785db525fceSDouglas Gilbert 				if (devip)
2786db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
2787db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
2788db525fceSDouglas Gilbert 				spin_unlock_irqrestore(&queued_arr_lock,
2789db525fceSDouglas Gilbert 						       iflags);
2790cbf67842SDouglas Gilbert 				if (scsi_debug_ndelay > 0) {
2791cbf67842SDouglas Gilbert 					if (sqcp->sd_hrtp)
2792cbf67842SDouglas Gilbert 						hrtimer_cancel(
2793cbf67842SDouglas Gilbert 							&sqcp->sd_hrtp->hrt);
2794cbf67842SDouglas Gilbert 				} else if (scsi_debug_delay > 0) {
2795cbf67842SDouglas Gilbert 					if (sqcp->cmnd_timerp)
2796cbf67842SDouglas Gilbert 						del_timer_sync(
2797cbf67842SDouglas Gilbert 							sqcp->cmnd_timerp);
2798cbf67842SDouglas Gilbert 				} else if (scsi_debug_delay < 0) {
2799cbf67842SDouglas Gilbert 					if (sqcp->tletp)
2800cbf67842SDouglas Gilbert 						tasklet_kill(sqcp->tletp);
2801cbf67842SDouglas Gilbert 				}
2802db525fceSDouglas Gilbert 				clear_bit(k, queued_in_use_bm);
2803db525fceSDouglas Gilbert 				spin_lock_irqsave(&queued_arr_lock, iflags);
28048dea0d02SFUJITA Tomonori 			}
28058dea0d02SFUJITA Tomonori 		}
2806cbf67842SDouglas Gilbert 	}
2807cbf67842SDouglas Gilbert 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
2808cbf67842SDouglas Gilbert }
2809cbf67842SDouglas Gilbert 
2810cbf67842SDouglas Gilbert /* Free queued command memory on heap */
2811cbf67842SDouglas Gilbert static void free_all_queued(void)
2812cbf67842SDouglas Gilbert {
2813cbf67842SDouglas Gilbert 	unsigned long iflags;
2814cbf67842SDouglas Gilbert 	int k;
2815cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
2816cbf67842SDouglas Gilbert 
2817cbf67842SDouglas Gilbert 	spin_lock_irqsave(&queued_arr_lock, iflags);
2818cbf67842SDouglas Gilbert 	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2819cbf67842SDouglas Gilbert 		sqcp = &queued_arr[k];
2820cbf67842SDouglas Gilbert 		kfree(sqcp->cmnd_timerp);
2821cbf67842SDouglas Gilbert 		sqcp->cmnd_timerp = NULL;
2822cbf67842SDouglas Gilbert 		kfree(sqcp->tletp);
2823cbf67842SDouglas Gilbert 		sqcp->tletp = NULL;
2824cbf67842SDouglas Gilbert 		kfree(sqcp->sd_hrtp);
2825cbf67842SDouglas Gilbert 		sqcp->sd_hrtp = NULL;
2826cbf67842SDouglas Gilbert 	}
28278dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
28281da177e4SLinus Torvalds }
28291da177e4SLinus Torvalds 
28301da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
28311da177e4SLinus Torvalds {
28321da177e4SLinus Torvalds 	++num_aborts;
2833cbf67842SDouglas Gilbert 	if (SCpnt) {
2834cbf67842SDouglas Gilbert 		if (SCpnt->device &&
2835cbf67842SDouglas Gilbert 		    (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts))
2836cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device, "%s\n",
2837cbf67842SDouglas Gilbert 				    __func__);
28381da177e4SLinus Torvalds 		stop_queued_cmnd(SCpnt);
2839cbf67842SDouglas Gilbert 	}
28401da177e4SLinus Torvalds 	return SUCCESS;
28411da177e4SLinus Torvalds }
28421da177e4SLinus Torvalds 
28431da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
28441da177e4SLinus Torvalds {
28451da177e4SLinus Torvalds 	struct sdebug_dev_info * devip;
28461da177e4SLinus Torvalds 
28471da177e4SLinus Torvalds 	++num_dev_resets;
2848cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
2849cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
2850cbf67842SDouglas Gilbert 
2851cbf67842SDouglas Gilbert 		if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)
2852cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
2853cbf67842SDouglas Gilbert 		devip = devInfoReg(sdp);
28541da177e4SLinus Torvalds 		if (devip)
2855cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
28561da177e4SLinus Torvalds 	}
28571da177e4SLinus Torvalds 	return SUCCESS;
28581da177e4SLinus Torvalds }
28591da177e4SLinus Torvalds 
2860cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
2861cbf67842SDouglas Gilbert {
2862cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
2863cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
2864cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
2865cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
2866cbf67842SDouglas Gilbert 	int k = 0;
2867cbf67842SDouglas Gilbert 
2868cbf67842SDouglas Gilbert 	++num_target_resets;
2869cbf67842SDouglas Gilbert 	if (!SCpnt)
2870cbf67842SDouglas Gilbert 		goto lie;
2871cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
2872cbf67842SDouglas Gilbert 	if (!sdp)
2873cbf67842SDouglas Gilbert 		goto lie;
2874cbf67842SDouglas Gilbert 	if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)
2875cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
2876cbf67842SDouglas Gilbert 	hp = sdp->host;
2877cbf67842SDouglas Gilbert 	if (!hp)
2878cbf67842SDouglas Gilbert 		goto lie;
2879cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
2880cbf67842SDouglas Gilbert 	if (sdbg_host) {
2881cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
2882cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
2883cbf67842SDouglas Gilbert 				    dev_list)
2884cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
2885cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
2886cbf67842SDouglas Gilbert 				++k;
2887cbf67842SDouglas Gilbert 			}
2888cbf67842SDouglas Gilbert 	}
2889cbf67842SDouglas Gilbert 	if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts)
2890cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
2891cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
2892cbf67842SDouglas Gilbert lie:
2893cbf67842SDouglas Gilbert 	return SUCCESS;
2894cbf67842SDouglas Gilbert }
2895cbf67842SDouglas Gilbert 
28961da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
28971da177e4SLinus Torvalds {
28981da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
2899cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
29001da177e4SLinus Torvalds         struct scsi_device * sdp;
29011da177e4SLinus Torvalds         struct Scsi_Host * hp;
2902cbf67842SDouglas Gilbert 	int k = 0;
29031da177e4SLinus Torvalds 
29041da177e4SLinus Torvalds 	++num_bus_resets;
2905cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
2906cbf67842SDouglas Gilbert 		goto lie;
2907cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
2908cbf67842SDouglas Gilbert 	if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)
2909cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
2910cbf67842SDouglas Gilbert 	hp = sdp->host;
2911cbf67842SDouglas Gilbert 	if (hp) {
2912d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
29131da177e4SLinus Torvalds 		if (sdbg_host) {
2914cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
29151da177e4SLinus Torvalds                                             &sdbg_host->dev_info_list,
2916cbf67842SDouglas Gilbert 					    dev_list) {
2917cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
2918cbf67842SDouglas Gilbert 				++k;
29191da177e4SLinus Torvalds 			}
29201da177e4SLinus Torvalds 		}
2921cbf67842SDouglas Gilbert 	}
2922cbf67842SDouglas Gilbert 	if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts)
2923cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
2924cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
2925cbf67842SDouglas Gilbert lie:
29261da177e4SLinus Torvalds 	return SUCCESS;
29271da177e4SLinus Torvalds }
29281da177e4SLinus Torvalds 
29291da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
29301da177e4SLinus Torvalds {
29311da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
2932cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
2933cbf67842SDouglas Gilbert 	int k = 0;
29341da177e4SLinus Torvalds 
29351da177e4SLinus Torvalds 	++num_host_resets;
2936cbf67842SDouglas Gilbert 	if ((SCpnt->device) && (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts))
2937cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
29381da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
29391da177e4SLinus Torvalds         list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2940cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
2941cbf67842SDouglas Gilbert 				    dev_list) {
2942cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
2943cbf67842SDouglas Gilbert 			++k;
2944cbf67842SDouglas Gilbert 		}
29451da177e4SLinus Torvalds         }
29461da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
29471da177e4SLinus Torvalds 	stop_all_queued();
2948cbf67842SDouglas Gilbert 	if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts)
2949cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
2950cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
29511da177e4SLinus Torvalds 	return SUCCESS;
29521da177e4SLinus Torvalds }
29531da177e4SLinus Torvalds 
2954f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
29555f2578e5SFUJITA Tomonori 				      unsigned long store_size)
29561da177e4SLinus Torvalds {
29571da177e4SLinus Torvalds 	struct partition * pp;
29581da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
29591da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
29601da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
29611da177e4SLinus Torvalds 
29621da177e4SLinus Torvalds 	/* assume partition table already zeroed */
2963f58b0efbSFUJITA Tomonori 	if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
29641da177e4SLinus Torvalds 		return;
29651da177e4SLinus Torvalds 	if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
29661da177e4SLinus Torvalds 		scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2967cbf67842SDouglas Gilbert 		pr_warn("%s: reducing partitions to %d\n", __func__,
2968cbf67842SDouglas Gilbert 			SDEBUG_MAX_PARTS);
29691da177e4SLinus Torvalds 	}
2970c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
29711da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
29721da177e4SLinus Torvalds 			   / scsi_debug_num_parts;
29731da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
29741da177e4SLinus Torvalds         starts[0] = sdebug_sectors_per;
29751da177e4SLinus Torvalds 	for (k = 1; k < scsi_debug_num_parts; ++k)
29761da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
29771da177e4SLinus Torvalds 			    * heads_by_sects;
29781da177e4SLinus Torvalds 	starts[scsi_debug_num_parts] = num_sectors;
29791da177e4SLinus Torvalds 	starts[scsi_debug_num_parts + 1] = 0;
29801da177e4SLinus Torvalds 
29811da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
29821da177e4SLinus Torvalds 	ramp[511] = 0xAA;
29831da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
29841da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
29851da177e4SLinus Torvalds 		start_sec = starts[k];
29861da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
29871da177e4SLinus Torvalds 		pp->boot_ind = 0;
29881da177e4SLinus Torvalds 
29891da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
29901da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
29911da177e4SLinus Torvalds 			   / sdebug_sectors_per;
29921da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
29931da177e4SLinus Torvalds 
29941da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
29951da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
29961da177e4SLinus Torvalds 			       / sdebug_sectors_per;
29971da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
29981da177e4SLinus Torvalds 
2999150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
3000150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
30011da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
30021da177e4SLinus Torvalds 	}
30031da177e4SLinus Torvalds }
30041da177e4SLinus Torvalds 
3005cbf67842SDouglas Gilbert static int
3006cbf67842SDouglas Gilbert schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
3007cbf67842SDouglas Gilbert 	      int scsi_result, int delta_jiff)
30081da177e4SLinus Torvalds {
3009cbf67842SDouglas Gilbert 	unsigned long iflags;
3010cd62b7daSDouglas Gilbert 	int k, num_in_q, qdepth, inject;
3011cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp = NULL;
30121da177e4SLinus Torvalds 	struct scsi_device *sdp = cmnd->device;
30131da177e4SLinus Torvalds 
3014cbf67842SDouglas Gilbert 	if (NULL == cmnd || NULL == devip) {
3015cbf67842SDouglas Gilbert 		pr_warn("%s: called with NULL cmnd or devip pointer\n",
3016cbf67842SDouglas Gilbert 			__func__);
3017cbf67842SDouglas Gilbert 		/* no particularly good error to report back */
3018cbf67842SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
30191da177e4SLinus Torvalds 	}
3020cbf67842SDouglas Gilbert 	if ((scsi_result) && (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
3021cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
3022cbf67842SDouglas Gilbert 			    __func__, scsi_result);
3023cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
3024cd62b7daSDouglas Gilbert 		goto respond_in_thread;
30251da177e4SLinus Torvalds 
3026cd62b7daSDouglas Gilbert 	/* schedule the response at a later time if resources permit */
30271da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
3028cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
3029cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
3030cbf67842SDouglas Gilbert 	inject = 0;
3031cd62b7daSDouglas Gilbert 	if ((qdepth > 0) && (num_in_q >= qdepth)) {
3032cd62b7daSDouglas Gilbert 		if (scsi_result) {
3033cd62b7daSDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
3034cd62b7daSDouglas Gilbert 			goto respond_in_thread;
3035cd62b7daSDouglas Gilbert 		} else
3036cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
3037cd62b7daSDouglas Gilbert 	} else if ((scsi_debug_every_nth != 0) &&
3038cd62b7daSDouglas Gilbert 		   (SCSI_DEBUG_OPT_RARE_TSF & scsi_debug_opts) &&
3039cd62b7daSDouglas Gilbert 		   (scsi_result == 0)) {
3040cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
3041cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
3042cbf67842SDouglas Gilbert 		     abs(scsi_debug_every_nth))) {
3043cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
3044cbf67842SDouglas Gilbert 			inject = 1;
3045cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
30461da177e4SLinus Torvalds 		}
3047cbf67842SDouglas Gilbert 	}
3048cbf67842SDouglas Gilbert 
3049cd62b7daSDouglas Gilbert 	k = find_first_zero_bit(queued_in_use_bm, scsi_debug_max_queue);
305078d4e5a0SDouglas Gilbert 	if (k >= scsi_debug_max_queue) {
30511da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
3052cd62b7daSDouglas Gilbert 		if (scsi_result)
3053cd62b7daSDouglas Gilbert 			goto respond_in_thread;
3054cd62b7daSDouglas Gilbert 		else if (SCSI_DEBUG_OPT_ALL_TSF & scsi_debug_opts)
3055cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
3056cbf67842SDouglas Gilbert 		if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts)
3057cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
3058cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
3059cd62b7daSDouglas Gilbert 				    __func__, scsi_debug_max_queue,
3060cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
3061cbf67842SDouglas Gilbert 						    "report: host busy"));
3062cd62b7daSDouglas Gilbert 		if (scsi_result)
3063cd62b7daSDouglas Gilbert 			goto respond_in_thread;
3064cd62b7daSDouglas Gilbert 		else
3065cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
30661da177e4SLinus Torvalds 	}
3067cbf67842SDouglas Gilbert 	__set_bit(k, queued_in_use_bm);
3068cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
3069cbf67842SDouglas Gilbert 	sqcp = &queued_arr[k];
30701da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
3071cbf67842SDouglas Gilbert 	cmnd->result = scsi_result;
30721da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
3073cbf67842SDouglas Gilbert 	if (delta_jiff > 0) {
3074cbf67842SDouglas Gilbert 		if (NULL == sqcp->cmnd_timerp) {
3075cbf67842SDouglas Gilbert 			sqcp->cmnd_timerp = kmalloc(sizeof(struct timer_list),
3076cbf67842SDouglas Gilbert 						    GFP_ATOMIC);
3077cbf67842SDouglas Gilbert 			if (NULL == sqcp->cmnd_timerp)
3078cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
3079cbf67842SDouglas Gilbert 			init_timer(sqcp->cmnd_timerp);
3080cbf67842SDouglas Gilbert 		}
3081cbf67842SDouglas Gilbert 		sqcp->cmnd_timerp->function = sdebug_q_cmd_complete;
3082cbf67842SDouglas Gilbert 		sqcp->cmnd_timerp->data = k;
3083cbf67842SDouglas Gilbert 		sqcp->cmnd_timerp->expires = get_jiffies_64() + delta_jiff;
3084cbf67842SDouglas Gilbert 		add_timer(sqcp->cmnd_timerp);
3085cbf67842SDouglas Gilbert 	} else if (scsi_debug_ndelay > 0) {
3086cbf67842SDouglas Gilbert 		ktime_t kt = ktime_set(0, scsi_debug_ndelay);
3087cbf67842SDouglas Gilbert 		struct sdebug_hrtimer *sd_hp = sqcp->sd_hrtp;
3088cbf67842SDouglas Gilbert 
3089cbf67842SDouglas Gilbert 		if (NULL == sd_hp) {
3090cbf67842SDouglas Gilbert 			sd_hp = kmalloc(sizeof(*sd_hp), GFP_ATOMIC);
3091cbf67842SDouglas Gilbert 			if (NULL == sd_hp)
3092cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
3093cbf67842SDouglas Gilbert 			sqcp->sd_hrtp = sd_hp;
3094cbf67842SDouglas Gilbert 			hrtimer_init(&sd_hp->hrt, CLOCK_MONOTONIC,
3095cbf67842SDouglas Gilbert 				     HRTIMER_MODE_REL);
3096cbf67842SDouglas Gilbert 			sd_hp->hrt.function = sdebug_q_cmd_hrt_complete;
3097cbf67842SDouglas Gilbert 			sd_hp->qa_indx = k;
3098cbf67842SDouglas Gilbert 		}
3099cbf67842SDouglas Gilbert 		hrtimer_start(&sd_hp->hrt, kt, HRTIMER_MODE_REL);
3100cbf67842SDouglas Gilbert 	} else {	/* delay < 0 */
3101cbf67842SDouglas Gilbert 		if (NULL == sqcp->tletp) {
3102cbf67842SDouglas Gilbert 			sqcp->tletp = kmalloc(sizeof(*sqcp->tletp),
3103cbf67842SDouglas Gilbert 					      GFP_ATOMIC);
3104cbf67842SDouglas Gilbert 			if (NULL == sqcp->tletp)
3105cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
3106cbf67842SDouglas Gilbert 			tasklet_init(sqcp->tletp,
3107cbf67842SDouglas Gilbert 				     sdebug_q_cmd_complete, k);
3108cbf67842SDouglas Gilbert 		}
3109cbf67842SDouglas Gilbert 		if (-1 == delta_jiff)
3110cbf67842SDouglas Gilbert 			tasklet_hi_schedule(sqcp->tletp);
3111cbf67842SDouglas Gilbert 		else
3112cbf67842SDouglas Gilbert 			tasklet_schedule(sqcp->tletp);
3113cbf67842SDouglas Gilbert 	}
3114cd62b7daSDouglas Gilbert 	if ((SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) &&
3115cd62b7daSDouglas Gilbert 	    (scsi_result == device_qfull_result))
3116cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3117cbf67842SDouglas Gilbert 			    "%s: num_in_q=%d +1, %s%s\n", __func__,
3118cbf67842SDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""),
3119cbf67842SDouglas Gilbert 			    "status: TASK SET FULL");
31201da177e4SLinus Torvalds 	return 0;
3121cd62b7daSDouglas Gilbert 
3122cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
3123cd62b7daSDouglas Gilbert 	cmnd->result = scsi_result;
3124cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
3125cd62b7daSDouglas Gilbert 	return 0;
31261da177e4SLinus Torvalds }
3127cbf67842SDouglas Gilbert 
312823183910SDouglas Gilbert /* Note: The following macros create attribute files in the
312923183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
313023183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
313123183910SDouglas Gilbert    as it can when the corresponding attribute in the
313223183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
313323183910SDouglas Gilbert  */
3134c65b1445SDouglas Gilbert module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
31355b94e232SMartin K. Petersen module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
31360759c666SAkinobu Mita module_param_named(clustering, scsi_debug_clustering, bool, S_IRUGO | S_IWUSR);
3137c65b1445SDouglas Gilbert module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
3138c65b1445SDouglas Gilbert module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
31395b94e232SMartin K. Petersen module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
31405b94e232SMartin K. Petersen module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
3141c65b1445SDouglas Gilbert module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
3142c65b1445SDouglas Gilbert module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
314323183910SDouglas Gilbert module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
314468aee7baSAkinobu Mita module_param_named(guard, scsi_debug_guard, uint, S_IRUGO);
3145cbf67842SDouglas Gilbert module_param_named(host_lock, scsi_debug_host_lock, bool, S_IRUGO | S_IWUSR);
31465b94e232SMartin K. Petersen module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO);
31475b94e232SMartin K. Petersen module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO);
31485b94e232SMartin K. Petersen module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO);
3149be1dd78dSEric Sandeen module_param_named(lbprz, scsi_debug_lbprz, int, S_IRUGO);
31505b94e232SMartin K. Petersen module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
3151c65b1445SDouglas Gilbert module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
315278d4e5a0SDouglas Gilbert module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);
3153cbf67842SDouglas Gilbert module_param_named(ndelay, scsi_debug_ndelay, int, S_IRUGO | S_IWUSR);
3154c65b1445SDouglas Gilbert module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
315578d4e5a0SDouglas Gilbert module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);
3156c65b1445SDouglas Gilbert module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
3157c65b1445SDouglas Gilbert module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
31585b94e232SMartin K. Petersen module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO);
3159c65b1445SDouglas Gilbert module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
31605b94e232SMartin K. Petersen module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
3161c65b1445SDouglas Gilbert module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
3162d986788bSMartin Pitt module_param_named(removable, scsi_debug_removable, bool, S_IRUGO | S_IWUSR);
3163c65b1445SDouglas Gilbert module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
31645b94e232SMartin K. Petersen module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
31655b94e232SMartin K. Petersen module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
31665b94e232SMartin K. Petersen module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
31675b94e232SMartin K. Petersen module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
31685b94e232SMartin K. Petersen module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
3169c65b1445SDouglas Gilbert module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
317023183910SDouglas Gilbert module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
317123183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
31725b94e232SMartin K. Petersen module_param_named(write_same_length, scsi_debug_write_same_length, int,
31735b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
31741da177e4SLinus Torvalds 
31751da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
31761da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
31771da177e4SLinus Torvalds MODULE_LICENSE("GPL");
31781da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION);
31791da177e4SLinus Torvalds 
31801da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
31815b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
31820759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
3183cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
3184c65b1445SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
31855b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
31865b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
3187c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
3188beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
318923183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
31905b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
3191cbf67842SDouglas Gilbert MODULE_PARM_DESC(host_lock, "use host_lock around all commands (def=0)");
31925b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
31935b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
31945b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
3195be1dd78dSEric Sandeen MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
31965b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
3197c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
3198cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
3199cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
3200c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
320178d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
32021da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
3203c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
32045b94e232SMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
32056f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
32065b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
32071da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
3208d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
3209e46b0344SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])");
3210ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
32115b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
32125b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
32136014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
32146014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
32155b94e232SMartin K. Petersen MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
32165b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
32175b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
32181da177e4SLinus Torvalds 
32191da177e4SLinus Torvalds static char sdebug_info[256];
32201da177e4SLinus Torvalds 
32211da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp)
32221da177e4SLinus Torvalds {
32231da177e4SLinus Torvalds 	sprintf(sdebug_info, "scsi_debug, version %s [%s], "
32241da177e4SLinus Torvalds 		"dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
32251da177e4SLinus Torvalds 		scsi_debug_version_date, scsi_debug_dev_size_mb,
32261da177e4SLinus Torvalds 		scsi_debug_opts);
32271da177e4SLinus Torvalds 	return sdebug_info;
32281da177e4SLinus Torvalds }
32291da177e4SLinus Torvalds 
3230cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
3231c8ed555aSAl Viro static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, int length)
32321da177e4SLinus Torvalds {
32331da177e4SLinus Torvalds 	char arr[16];
3234c8ed555aSAl Viro 	int opts;
32351da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
32361da177e4SLinus Torvalds 
32371da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
32381da177e4SLinus Torvalds 		return -EACCES;
32391da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
32401da177e4SLinus Torvalds 	arr[minLen] = '\0';
3241c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
32421da177e4SLinus Torvalds 		return -EINVAL;
3243c8ed555aSAl Viro 	scsi_debug_opts = opts;
32441da177e4SLinus Torvalds 	if (scsi_debug_every_nth != 0)
3245cbf67842SDouglas Gilbert 		atomic_set(&sdebug_cmnd_count, 0);
32461da177e4SLinus Torvalds 	return length;
32471da177e4SLinus Torvalds }
3248c8ed555aSAl Viro 
3249cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
3250cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
3251cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
3252c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
3253c8ed555aSAl Viro {
3254cbf67842SDouglas Gilbert 	int f, l;
3255cbf67842SDouglas Gilbert 	char b[32];
3256cbf67842SDouglas Gilbert 
3257cbf67842SDouglas Gilbert 	if (scsi_debug_every_nth > 0)
3258cbf67842SDouglas Gilbert 		snprintf(b, sizeof(b), " (curr:%d)",
3259cbf67842SDouglas Gilbert 			 ((SCSI_DEBUG_OPT_RARE_TSF & scsi_debug_opts) ?
3260cbf67842SDouglas Gilbert 				atomic_read(&sdebug_a_tsf) :
3261cbf67842SDouglas Gilbert 				atomic_read(&sdebug_cmnd_count)));
3262cbf67842SDouglas Gilbert 	else
3263cbf67842SDouglas Gilbert 		b[0] = '\0';
3264cbf67842SDouglas Gilbert 
3265cbf67842SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n"
32661da177e4SLinus Torvalds 		"num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
3267cbf67842SDouglas Gilbert 		"every_nth=%d%s\n"
3268cbf67842SDouglas Gilbert 		"delay=%d, ndelay=%d, max_luns=%d, q_completions=%d\n"
32691da177e4SLinus Torvalds 		"sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
3270cbf67842SDouglas Gilbert 		"command aborts=%d; RESETs: device=%d, target=%d, bus=%d, "
3271cbf67842SDouglas Gilbert 		"host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d "
3272cbf67842SDouglas Gilbert 		"usec_in_jiffy=%lu\n",
3273cbf67842SDouglas Gilbert 		SCSI_DEBUG_VERSION, scsi_debug_version_date,
3274cbf67842SDouglas Gilbert 		scsi_debug_num_tgts, scsi_debug_dev_size_mb, scsi_debug_opts,
3275cbf67842SDouglas Gilbert 		scsi_debug_every_nth, b, scsi_debug_delay, scsi_debug_ndelay,
3276cbf67842SDouglas Gilbert 		scsi_debug_max_luns, atomic_read(&sdebug_completions),
3277597136abSMartin K. Petersen 		scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
3278cbf67842SDouglas Gilbert 		sdebug_sectors_per, num_aborts, num_dev_resets,
3279cbf67842SDouglas Gilbert 		num_target_resets, num_bus_resets, num_host_resets,
3280cbf67842SDouglas Gilbert 		dix_reads, dix_writes, dif_errors, TICK_NSEC / 1000);
3281cbf67842SDouglas Gilbert 
3282cbf67842SDouglas Gilbert 	f = find_first_bit(queued_in_use_bm, scsi_debug_max_queue);
3283cbf67842SDouglas Gilbert 	if (f != scsi_debug_max_queue) {
3284cbf67842SDouglas Gilbert 		l = find_last_bit(queued_in_use_bm, scsi_debug_max_queue);
3285cbf67842SDouglas Gilbert 		seq_printf(m, "   %s BUSY: first,last bits set: %d,%d\n",
3286cbf67842SDouglas Gilbert 			   "queued_in_use_bm", f, l);
3287cbf67842SDouglas Gilbert 	}
3288c8ed555aSAl Viro 	return 0;
32891da177e4SLinus Torvalds }
32901da177e4SLinus Torvalds 
329182069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
32921da177e4SLinus Torvalds {
32931da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
32941da177e4SLinus Torvalds }
3295cbf67842SDouglas Gilbert /* Returns -EBUSY if delay is being changed and commands are queued */
329682069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
329782069379SAkinobu Mita 			   size_t count)
32981da177e4SLinus Torvalds {
3299cbf67842SDouglas Gilbert 	int delay, res;
33001da177e4SLinus Torvalds 
3301cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &delay))) {
3302cbf67842SDouglas Gilbert 		res = count;
3303cbf67842SDouglas Gilbert 		if (scsi_debug_delay != delay) {
3304cbf67842SDouglas Gilbert 			unsigned long iflags;
3305cbf67842SDouglas Gilbert 			int k;
3306cbf67842SDouglas Gilbert 
3307cbf67842SDouglas Gilbert 			spin_lock_irqsave(&queued_arr_lock, iflags);
3308cbf67842SDouglas Gilbert 			k = find_first_bit(queued_in_use_bm,
3309cbf67842SDouglas Gilbert 					   scsi_debug_max_queue);
3310cbf67842SDouglas Gilbert 			if (k != scsi_debug_max_queue)
3311cbf67842SDouglas Gilbert 				res = -EBUSY;	/* have queued commands */
3312cbf67842SDouglas Gilbert 			else {
33131da177e4SLinus Torvalds 				scsi_debug_delay = delay;
3314cbf67842SDouglas Gilbert 				scsi_debug_ndelay = 0;
33151da177e4SLinus Torvalds 			}
3316cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
3317cbf67842SDouglas Gilbert 		}
3318cbf67842SDouglas Gilbert 		return res;
33191da177e4SLinus Torvalds 	}
33201da177e4SLinus Torvalds 	return -EINVAL;
33211da177e4SLinus Torvalds }
332282069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
33231da177e4SLinus Torvalds 
3324cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
3325cbf67842SDouglas Gilbert {
3326cbf67842SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ndelay);
3327cbf67842SDouglas Gilbert }
3328cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
3329cbf67842SDouglas Gilbert /* If > 0 and accepted then scsi_debug_delay is set to DELAY_OVERRIDDEN */
3330cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
3331cbf67842SDouglas Gilbert 			   size_t count)
3332cbf67842SDouglas Gilbert {
3333cbf67842SDouglas Gilbert 	unsigned long iflags;
3334cbf67842SDouglas Gilbert 	int ndelay, res, k;
3335cbf67842SDouglas Gilbert 
3336cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
3337cbf67842SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < 1000000000)) {
3338cbf67842SDouglas Gilbert 		res = count;
3339cbf67842SDouglas Gilbert 		if (scsi_debug_ndelay != ndelay) {
3340cbf67842SDouglas Gilbert 			spin_lock_irqsave(&queued_arr_lock, iflags);
3341cbf67842SDouglas Gilbert 			k = find_first_bit(queued_in_use_bm,
3342cbf67842SDouglas Gilbert 					   scsi_debug_max_queue);
3343cbf67842SDouglas Gilbert 			if (k != scsi_debug_max_queue)
3344cbf67842SDouglas Gilbert 				res = -EBUSY;	/* have queued commands */
3345cbf67842SDouglas Gilbert 			else {
3346cbf67842SDouglas Gilbert 				scsi_debug_ndelay = ndelay;
3347cbf67842SDouglas Gilbert 				scsi_debug_delay = ndelay ? DELAY_OVERRIDDEN
3348cbf67842SDouglas Gilbert 							  : DEF_DELAY;
3349cbf67842SDouglas Gilbert 			}
3350cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
3351cbf67842SDouglas Gilbert 		}
3352cbf67842SDouglas Gilbert 		return res;
3353cbf67842SDouglas Gilbert 	}
3354cbf67842SDouglas Gilbert 	return -EINVAL;
3355cbf67842SDouglas Gilbert }
3356cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
3357cbf67842SDouglas Gilbert 
335882069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
33591da177e4SLinus Torvalds {
33601da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
33611da177e4SLinus Torvalds }
33621da177e4SLinus Torvalds 
336382069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
336482069379SAkinobu Mita 			  size_t count)
33651da177e4SLinus Torvalds {
33661da177e4SLinus Torvalds         int opts;
33671da177e4SLinus Torvalds 	char work[20];
33681da177e4SLinus Torvalds 
33691da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
337048a96876SRasmus Villemoes 		if (0 == strncasecmp(work,"0x", 2)) {
33711da177e4SLinus Torvalds 			if (1 == sscanf(&work[2], "%x", &opts))
33721da177e4SLinus Torvalds 				goto opts_done;
33731da177e4SLinus Torvalds 		} else {
33741da177e4SLinus Torvalds 			if (1 == sscanf(work, "%d", &opts))
33751da177e4SLinus Torvalds 				goto opts_done;
33761da177e4SLinus Torvalds 		}
33771da177e4SLinus Torvalds 	}
33781da177e4SLinus Torvalds 	return -EINVAL;
33791da177e4SLinus Torvalds opts_done:
33801da177e4SLinus Torvalds 	scsi_debug_opts = opts;
3381cbf67842SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
3382cbf67842SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
33831da177e4SLinus Torvalds 	return count;
33841da177e4SLinus Torvalds }
338582069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
33861da177e4SLinus Torvalds 
338782069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
33881da177e4SLinus Torvalds {
33891da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
33901da177e4SLinus Torvalds }
339182069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
339282069379SAkinobu Mita 			   size_t count)
33931da177e4SLinus Torvalds {
33941da177e4SLinus Torvalds         int n;
33951da177e4SLinus Torvalds 
33961da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
33971da177e4SLinus Torvalds 		scsi_debug_ptype = n;
33981da177e4SLinus Torvalds 		return count;
33991da177e4SLinus Torvalds 	}
34001da177e4SLinus Torvalds 	return -EINVAL;
34011da177e4SLinus Torvalds }
340282069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
34031da177e4SLinus Torvalds 
340482069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
34051da177e4SLinus Torvalds {
34061da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
34071da177e4SLinus Torvalds }
340882069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
340982069379SAkinobu Mita 			    size_t count)
34101da177e4SLinus Torvalds {
34111da177e4SLinus Torvalds         int n;
34121da177e4SLinus Torvalds 
34131da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
34141da177e4SLinus Torvalds 		scsi_debug_dsense = n;
34151da177e4SLinus Torvalds 		return count;
34161da177e4SLinus Torvalds 	}
34171da177e4SLinus Torvalds 	return -EINVAL;
34181da177e4SLinus Torvalds }
341982069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
34201da177e4SLinus Torvalds 
342182069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
342223183910SDouglas Gilbert {
342323183910SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
342423183910SDouglas Gilbert }
342582069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
342682069379SAkinobu Mita 			     size_t count)
342723183910SDouglas Gilbert {
342823183910SDouglas Gilbert         int n;
342923183910SDouglas Gilbert 
343023183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3431cbf67842SDouglas Gilbert 		n = (n > 0);
3432cbf67842SDouglas Gilbert 		scsi_debug_fake_rw = (scsi_debug_fake_rw > 0);
3433cbf67842SDouglas Gilbert 		if (scsi_debug_fake_rw != n) {
3434cbf67842SDouglas Gilbert 			if ((0 == n) && (NULL == fake_storep)) {
3435cbf67842SDouglas Gilbert 				unsigned long sz =
3436cbf67842SDouglas Gilbert 					(unsigned long)scsi_debug_dev_size_mb *
3437cbf67842SDouglas Gilbert 					1048576;
3438cbf67842SDouglas Gilbert 
3439cbf67842SDouglas Gilbert 				fake_storep = vmalloc(sz);
3440cbf67842SDouglas Gilbert 				if (NULL == fake_storep) {
3441cbf67842SDouglas Gilbert 					pr_err("%s: out of memory, 9\n",
3442cbf67842SDouglas Gilbert 					       __func__);
3443cbf67842SDouglas Gilbert 					return -ENOMEM;
3444cbf67842SDouglas Gilbert 				}
3445cbf67842SDouglas Gilbert 				memset(fake_storep, 0, sz);
3446cbf67842SDouglas Gilbert 			}
344723183910SDouglas Gilbert 			scsi_debug_fake_rw = n;
3448cbf67842SDouglas Gilbert 		}
344923183910SDouglas Gilbert 		return count;
345023183910SDouglas Gilbert 	}
345123183910SDouglas Gilbert 	return -EINVAL;
345223183910SDouglas Gilbert }
345382069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
345423183910SDouglas Gilbert 
345582069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
3456c65b1445SDouglas Gilbert {
3457c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
3458c65b1445SDouglas Gilbert }
345982069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
346082069379SAkinobu Mita 			      size_t count)
3461c65b1445SDouglas Gilbert {
3462c65b1445SDouglas Gilbert         int n;
3463c65b1445SDouglas Gilbert 
3464c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3465c65b1445SDouglas Gilbert 		scsi_debug_no_lun_0 = n;
3466c65b1445SDouglas Gilbert 		return count;
3467c65b1445SDouglas Gilbert 	}
3468c65b1445SDouglas Gilbert 	return -EINVAL;
3469c65b1445SDouglas Gilbert }
347082069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
3471c65b1445SDouglas Gilbert 
347282069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
34731da177e4SLinus Torvalds {
34741da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
34751da177e4SLinus Torvalds }
347682069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
347782069379SAkinobu Mita 			      size_t count)
34781da177e4SLinus Torvalds {
34791da177e4SLinus Torvalds         int n;
34801da177e4SLinus Torvalds 
34811da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
34821da177e4SLinus Torvalds 		scsi_debug_num_tgts = n;
34831da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
34841da177e4SLinus Torvalds 		return count;
34851da177e4SLinus Torvalds 	}
34861da177e4SLinus Torvalds 	return -EINVAL;
34871da177e4SLinus Torvalds }
348882069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
34891da177e4SLinus Torvalds 
349082069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
34911da177e4SLinus Torvalds {
34921da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
34931da177e4SLinus Torvalds }
349482069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
34951da177e4SLinus Torvalds 
349682069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
34971da177e4SLinus Torvalds {
34981da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
34991da177e4SLinus Torvalds }
350082069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
35011da177e4SLinus Torvalds 
350282069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
35031da177e4SLinus Torvalds {
35041da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
35051da177e4SLinus Torvalds }
350682069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
350782069379SAkinobu Mita 			       size_t count)
35081da177e4SLinus Torvalds {
35091da177e4SLinus Torvalds         int nth;
35101da177e4SLinus Torvalds 
35111da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
35121da177e4SLinus Torvalds 		scsi_debug_every_nth = nth;
3513cbf67842SDouglas Gilbert 		atomic_set(&sdebug_cmnd_count, 0);
35141da177e4SLinus Torvalds 		return count;
35151da177e4SLinus Torvalds 	}
35161da177e4SLinus Torvalds 	return -EINVAL;
35171da177e4SLinus Torvalds }
351882069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
35191da177e4SLinus Torvalds 
352082069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
35211da177e4SLinus Torvalds {
35221da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
35231da177e4SLinus Torvalds }
352482069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
352582069379SAkinobu Mita 			      size_t count)
35261da177e4SLinus Torvalds {
35271da177e4SLinus Torvalds         int n;
35281da177e4SLinus Torvalds 
35291da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
35301da177e4SLinus Torvalds 		scsi_debug_max_luns = n;
35311da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
35321da177e4SLinus Torvalds 		return count;
35331da177e4SLinus Torvalds 	}
35341da177e4SLinus Torvalds 	return -EINVAL;
35351da177e4SLinus Torvalds }
353682069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
35371da177e4SLinus Torvalds 
353882069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
353978d4e5a0SDouglas Gilbert {
354078d4e5a0SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue);
354178d4e5a0SDouglas Gilbert }
3542cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
3543cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
354482069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
354582069379SAkinobu Mita 			       size_t count)
354678d4e5a0SDouglas Gilbert {
3547cbf67842SDouglas Gilbert 	unsigned long iflags;
3548cbf67842SDouglas Gilbert 	int n, k;
354978d4e5a0SDouglas Gilbert 
355078d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
355178d4e5a0SDouglas Gilbert 	    (n <= SCSI_DEBUG_CANQUEUE)) {
3552cbf67842SDouglas Gilbert 		spin_lock_irqsave(&queued_arr_lock, iflags);
3553cbf67842SDouglas Gilbert 		k = find_last_bit(queued_in_use_bm, SCSI_DEBUG_CANQUEUE);
355478d4e5a0SDouglas Gilbert 		scsi_debug_max_queue = n;
3555cbf67842SDouglas Gilbert 		if (SCSI_DEBUG_CANQUEUE == k)
3556cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3557cbf67842SDouglas Gilbert 		else if (k >= n)
3558cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
3559cbf67842SDouglas Gilbert 		else
3560cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3561cbf67842SDouglas Gilbert 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
356278d4e5a0SDouglas Gilbert 		return count;
356378d4e5a0SDouglas Gilbert 	}
356478d4e5a0SDouglas Gilbert 	return -EINVAL;
356578d4e5a0SDouglas Gilbert }
356682069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
356778d4e5a0SDouglas Gilbert 
356882069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
356978d4e5a0SDouglas Gilbert {
357078d4e5a0SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld);
357178d4e5a0SDouglas Gilbert }
357282069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
357378d4e5a0SDouglas Gilbert 
357482069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
35751da177e4SLinus Torvalds {
35761da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
35771da177e4SLinus Torvalds }
357882069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
35791da177e4SLinus Torvalds 
358082069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
3581c65b1445SDouglas Gilbert {
3582c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
3583c65b1445SDouglas Gilbert }
358482069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
358582069379SAkinobu Mita 				size_t count)
3586c65b1445SDouglas Gilbert {
3587c65b1445SDouglas Gilbert         int n;
3588c65b1445SDouglas Gilbert 
3589c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3590c65b1445SDouglas Gilbert 		scsi_debug_virtual_gb = n;
359128898873SFUJITA Tomonori 
359228898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
359328898873SFUJITA Tomonori 
3594c65b1445SDouglas Gilbert 		return count;
3595c65b1445SDouglas Gilbert 	}
3596c65b1445SDouglas Gilbert 	return -EINVAL;
3597c65b1445SDouglas Gilbert }
359882069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
3599c65b1445SDouglas Gilbert 
360082069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
36011da177e4SLinus Torvalds {
36021da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
36031da177e4SLinus Torvalds }
36041da177e4SLinus Torvalds 
360582069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
360682069379SAkinobu Mita 			      size_t count)
36071da177e4SLinus Torvalds {
36081da177e4SLinus Torvalds 	int delta_hosts;
36091da177e4SLinus Torvalds 
3610f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
36111da177e4SLinus Torvalds 		return -EINVAL;
36121da177e4SLinus Torvalds 	if (delta_hosts > 0) {
36131da177e4SLinus Torvalds 		do {
36141da177e4SLinus Torvalds 			sdebug_add_adapter();
36151da177e4SLinus Torvalds 		} while (--delta_hosts);
36161da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
36171da177e4SLinus Torvalds 		do {
36181da177e4SLinus Torvalds 			sdebug_remove_adapter();
36191da177e4SLinus Torvalds 		} while (++delta_hosts);
36201da177e4SLinus Torvalds 	}
36211da177e4SLinus Torvalds 	return count;
36221da177e4SLinus Torvalds }
362382069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
36241da177e4SLinus Torvalds 
362582069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
362623183910SDouglas Gilbert {
362723183910SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
362823183910SDouglas Gilbert }
362982069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
363082069379SAkinobu Mita 				    size_t count)
363123183910SDouglas Gilbert {
363223183910SDouglas Gilbert 	int n;
363323183910SDouglas Gilbert 
363423183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
363523183910SDouglas Gilbert 		scsi_debug_vpd_use_hostno = n;
363623183910SDouglas Gilbert 		return count;
363723183910SDouglas Gilbert 	}
363823183910SDouglas Gilbert 	return -EINVAL;
363923183910SDouglas Gilbert }
364082069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
364123183910SDouglas Gilbert 
364282069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
3643597136abSMartin K. Petersen {
3644597136abSMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
3645597136abSMartin K. Petersen }
364682069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
3647597136abSMartin K. Petersen 
364882069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
3649c6a44287SMartin K. Petersen {
3650c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
3651c6a44287SMartin K. Petersen }
365282069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
3653c6a44287SMartin K. Petersen 
365482069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
3655c6a44287SMartin K. Petersen {
3656c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
3657c6a44287SMartin K. Petersen }
365882069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
3659c6a44287SMartin K. Petersen 
366082069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
3661c6a44287SMartin K. Petersen {
366268aee7baSAkinobu Mita 	return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_guard);
3663c6a44287SMartin K. Petersen }
366482069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
3665c6a44287SMartin K. Petersen 
366682069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
3667c6a44287SMartin K. Petersen {
3668c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
3669c6a44287SMartin K. Petersen }
367082069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
3671c6a44287SMartin K. Petersen 
367282069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
367344d92694SMartin K. Petersen {
367444d92694SMartin K. Petersen 	ssize_t count;
367544d92694SMartin K. Petersen 
36765b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
367744d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
367844d92694SMartin K. Petersen 				 sdebug_store_sectors);
367944d92694SMartin K. Petersen 
368044d92694SMartin K. Petersen 	count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
368144d92694SMartin K. Petersen 
368244d92694SMartin K. Petersen 	buf[count++] = '\n';
368344d92694SMartin K. Petersen 	buf[count++] = 0;
368444d92694SMartin K. Petersen 
368544d92694SMartin K. Petersen 	return count;
368644d92694SMartin K. Petersen }
368782069379SAkinobu Mita static DRIVER_ATTR_RO(map);
368844d92694SMartin K. Petersen 
368982069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
3690d986788bSMartin Pitt {
3691d986788bSMartin Pitt 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_removable ? 1 : 0);
3692d986788bSMartin Pitt }
369382069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
369482069379SAkinobu Mita 			       size_t count)
3695d986788bSMartin Pitt {
3696d986788bSMartin Pitt 	int n;
3697d986788bSMartin Pitt 
3698d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3699d986788bSMartin Pitt 		scsi_debug_removable = (n > 0);
3700d986788bSMartin Pitt 		return count;
3701d986788bSMartin Pitt 	}
3702d986788bSMartin Pitt 	return -EINVAL;
3703d986788bSMartin Pitt }
370482069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
3705d986788bSMartin Pitt 
3706cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
3707cbf67842SDouglas Gilbert {
3708cbf67842SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!scsi_debug_host_lock);
3709cbf67842SDouglas Gilbert }
3710cbf67842SDouglas Gilbert /* Returns -EBUSY if host_lock is being changed and commands are queued */
3711cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
3712cbf67842SDouglas Gilbert 			       size_t count)
3713cbf67842SDouglas Gilbert {
3714cbf67842SDouglas Gilbert 	int n, res;
3715cbf67842SDouglas Gilbert 
3716cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3717cbf67842SDouglas Gilbert 		bool new_host_lock = (n > 0);
3718cbf67842SDouglas Gilbert 
3719cbf67842SDouglas Gilbert 		res = count;
3720cbf67842SDouglas Gilbert 		if (new_host_lock != scsi_debug_host_lock) {
3721cbf67842SDouglas Gilbert 			unsigned long iflags;
3722cbf67842SDouglas Gilbert 			int k;
3723cbf67842SDouglas Gilbert 
3724cbf67842SDouglas Gilbert 			spin_lock_irqsave(&queued_arr_lock, iflags);
3725cbf67842SDouglas Gilbert 			k = find_first_bit(queued_in_use_bm,
3726cbf67842SDouglas Gilbert 					   scsi_debug_max_queue);
3727cbf67842SDouglas Gilbert 			if (k != scsi_debug_max_queue)
3728cbf67842SDouglas Gilbert 				res = -EBUSY;	/* have queued commands */
3729cbf67842SDouglas Gilbert 			else
3730cbf67842SDouglas Gilbert 				scsi_debug_host_lock = new_host_lock;
3731cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
3732cbf67842SDouglas Gilbert 		}
3733cbf67842SDouglas Gilbert 		return res;
3734cbf67842SDouglas Gilbert 	}
3735cbf67842SDouglas Gilbert 	return -EINVAL;
3736cbf67842SDouglas Gilbert }
3737cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
3738cbf67842SDouglas Gilbert 
3739cbf67842SDouglas Gilbert 
374082069379SAkinobu Mita /* Note: The following array creates attribute files in the
374123183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
374223183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
374323183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
374423183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
374523183910SDouglas Gilbert  */
37466ecaff7fSRandy Dunlap 
374782069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
374882069379SAkinobu Mita 	&driver_attr_delay.attr,
374982069379SAkinobu Mita 	&driver_attr_opts.attr,
375082069379SAkinobu Mita 	&driver_attr_ptype.attr,
375182069379SAkinobu Mita 	&driver_attr_dsense.attr,
375282069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
375382069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
375482069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
375582069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
375682069379SAkinobu Mita 	&driver_attr_num_parts.attr,
375782069379SAkinobu Mita 	&driver_attr_every_nth.attr,
375882069379SAkinobu Mita 	&driver_attr_max_luns.attr,
375982069379SAkinobu Mita 	&driver_attr_max_queue.attr,
376082069379SAkinobu Mita 	&driver_attr_no_uld.attr,
376182069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
376282069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
376382069379SAkinobu Mita 	&driver_attr_add_host.attr,
376482069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
376582069379SAkinobu Mita 	&driver_attr_sector_size.attr,
376682069379SAkinobu Mita 	&driver_attr_dix.attr,
376782069379SAkinobu Mita 	&driver_attr_dif.attr,
376882069379SAkinobu Mita 	&driver_attr_guard.attr,
376982069379SAkinobu Mita 	&driver_attr_ato.attr,
377082069379SAkinobu Mita 	&driver_attr_map.attr,
377182069379SAkinobu Mita 	&driver_attr_removable.attr,
3772cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
3773cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
377482069379SAkinobu Mita 	NULL,
377582069379SAkinobu Mita };
377682069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
37771da177e4SLinus Torvalds 
377811ddcecaSAkinobu Mita static struct device *pseudo_primary;
37798dea0d02SFUJITA Tomonori 
37801da177e4SLinus Torvalds static int __init scsi_debug_init(void)
37811da177e4SLinus Torvalds {
37825f2578e5SFUJITA Tomonori 	unsigned long sz;
37831da177e4SLinus Torvalds 	int host_to_add;
37841da177e4SLinus Torvalds 	int k;
37856ecaff7fSRandy Dunlap 	int ret;
37861da177e4SLinus Torvalds 
3787cbf67842SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
3788cbf67842SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
3789cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
3790cbf67842SDouglas Gilbert 
3791cbf67842SDouglas Gilbert 	if (scsi_debug_ndelay >= 1000000000) {
3792cbf67842SDouglas Gilbert 		pr_warn("%s: ndelay must be less than 1 second, ignored\n",
3793cbf67842SDouglas Gilbert 			__func__);
3794cbf67842SDouglas Gilbert 		scsi_debug_ndelay = 0;
3795cbf67842SDouglas Gilbert 	} else if (scsi_debug_ndelay > 0)
3796cbf67842SDouglas Gilbert 		scsi_debug_delay = DELAY_OVERRIDDEN;
3797cbf67842SDouglas Gilbert 
3798597136abSMartin K. Petersen 	switch (scsi_debug_sector_size) {
3799597136abSMartin K. Petersen 	case  512:
3800597136abSMartin K. Petersen 	case 1024:
3801597136abSMartin K. Petersen 	case 2048:
3802597136abSMartin K. Petersen 	case 4096:
3803597136abSMartin K. Petersen 		break;
3804597136abSMartin K. Petersen 	default:
3805cbf67842SDouglas Gilbert 		pr_err("%s: invalid sector_size %d\n", __func__,
3806597136abSMartin K. Petersen 		       scsi_debug_sector_size);
3807597136abSMartin K. Petersen 		return -EINVAL;
3808597136abSMartin K. Petersen 	}
3809597136abSMartin K. Petersen 
3810c6a44287SMartin K. Petersen 	switch (scsi_debug_dif) {
3811c6a44287SMartin K. Petersen 
3812c6a44287SMartin K. Petersen 	case SD_DIF_TYPE0_PROTECTION:
3813c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
3814395cef03SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
3815c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
3816c6a44287SMartin K. Petersen 		break;
3817c6a44287SMartin K. Petersen 
3818c6a44287SMartin K. Petersen 	default:
3819cbf67842SDouglas Gilbert 		pr_err("%s: dif must be 0, 1, 2 or 3\n", __func__);
3820c6a44287SMartin K. Petersen 		return -EINVAL;
3821c6a44287SMartin K. Petersen 	}
3822c6a44287SMartin K. Petersen 
3823c6a44287SMartin K. Petersen 	if (scsi_debug_guard > 1) {
3824cbf67842SDouglas Gilbert 		pr_err("%s: guard must be 0 or 1\n", __func__);
3825c6a44287SMartin K. Petersen 		return -EINVAL;
3826c6a44287SMartin K. Petersen 	}
3827c6a44287SMartin K. Petersen 
3828c6a44287SMartin K. Petersen 	if (scsi_debug_ato > 1) {
3829cbf67842SDouglas Gilbert 		pr_err("%s: ato must be 0 or 1\n", __func__);
3830c6a44287SMartin K. Petersen 		return -EINVAL;
3831c6a44287SMartin K. Petersen 	}
3832c6a44287SMartin K. Petersen 
3833ea61fca5SMartin K. Petersen 	if (scsi_debug_physblk_exp > 15) {
3834cbf67842SDouglas Gilbert 		pr_err("%s: invalid physblk_exp %u\n", __func__,
3835ea61fca5SMartin K. Petersen 		       scsi_debug_physblk_exp);
3836ea61fca5SMartin K. Petersen 		return -EINVAL;
3837ea61fca5SMartin K. Petersen 	}
3838ea61fca5SMartin K. Petersen 
3839ea61fca5SMartin K. Petersen 	if (scsi_debug_lowest_aligned > 0x3fff) {
3840cbf67842SDouglas Gilbert 		pr_err("%s: lowest_aligned too big: %u\n", __func__,
3841ea61fca5SMartin K. Petersen 		       scsi_debug_lowest_aligned);
3842ea61fca5SMartin K. Petersen 		return -EINVAL;
3843ea61fca5SMartin K. Petersen 	}
3844ea61fca5SMartin K. Petersen 
38451da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb < 1)
38461da177e4SLinus Torvalds 		scsi_debug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
38475f2578e5SFUJITA Tomonori 	sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
3848597136abSMartin K. Petersen 	sdebug_store_sectors = sz / scsi_debug_sector_size;
384928898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
38501da177e4SLinus Torvalds 
38511da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
38521da177e4SLinus Torvalds 	sdebug_heads = 8;
38531da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
38541da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb >= 16)
38551da177e4SLinus Torvalds 		sdebug_heads = 32;
38561da177e4SLinus Torvalds 	else if (scsi_debug_dev_size_mb >= 256)
38571da177e4SLinus Torvalds 		sdebug_heads = 64;
38581da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
38591da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
38601da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
38611da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
38621da177e4SLinus Torvalds 		sdebug_heads = 255;
38631da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
38641da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
38651da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
38661da177e4SLinus Torvalds 	}
38671da177e4SLinus Torvalds 
3868cbf67842SDouglas Gilbert 	if (0 == scsi_debug_fake_rw) {
38691da177e4SLinus Torvalds 		fake_storep = vmalloc(sz);
38701da177e4SLinus Torvalds 		if (NULL == fake_storep) {
3871cbf67842SDouglas Gilbert 			pr_err("%s: out of memory, 1\n", __func__);
38721da177e4SLinus Torvalds 			return -ENOMEM;
38731da177e4SLinus Torvalds 		}
38741da177e4SLinus Torvalds 		memset(fake_storep, 0, sz);
38751da177e4SLinus Torvalds 		if (scsi_debug_num_parts > 0)
3876f58b0efbSFUJITA Tomonori 			sdebug_build_parts(fake_storep, sz);
3877cbf67842SDouglas Gilbert 	}
38781da177e4SLinus Torvalds 
38797cb69d03SAkinobu Mita 	if (scsi_debug_dix) {
3880c6a44287SMartin K. Petersen 		int dif_size;
3881c6a44287SMartin K. Petersen 
3882c6a44287SMartin K. Petersen 		dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
3883c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
3884c6a44287SMartin K. Petersen 
3885cbf67842SDouglas Gilbert 		pr_err("%s: dif_storep %u bytes @ %p\n", __func__, dif_size,
3886cbf67842SDouglas Gilbert 			dif_storep);
3887c6a44287SMartin K. Petersen 
3888c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
3889cbf67842SDouglas Gilbert 			pr_err("%s: out of mem. (DIX)\n", __func__);
3890c6a44287SMartin K. Petersen 			ret = -ENOMEM;
3891c6a44287SMartin K. Petersen 			goto free_vm;
3892c6a44287SMartin K. Petersen 		}
3893c6a44287SMartin K. Petersen 
3894c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
3895c6a44287SMartin K. Petersen 	}
3896c6a44287SMartin K. Petersen 
38975b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
38985b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
38996014759cSMartin K. Petersen 		scsi_debug_unmap_max_blocks =
39006014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU);
39016014759cSMartin K. Petersen 
39026014759cSMartin K. Petersen 		scsi_debug_unmap_max_desc =
39036014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_max_desc, 0U, 256U);
39046014759cSMartin K. Petersen 
39056014759cSMartin K. Petersen 		scsi_debug_unmap_granularity =
39066014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU);
39076014759cSMartin K. Petersen 
39086014759cSMartin K. Petersen 		if (scsi_debug_unmap_alignment &&
3909ac17078aSAkinobu Mita 		    scsi_debug_unmap_granularity <=
3910ac17078aSAkinobu Mita 		    scsi_debug_unmap_alignment) {
3911cbf67842SDouglas Gilbert 			pr_err("%s: ERR: unmap_granularity <= unmap_alignment\n",
391244d92694SMartin K. Petersen 			       __func__);
391344d92694SMartin K. Petersen 			return -EINVAL;
391444d92694SMartin K. Petersen 		}
391544d92694SMartin K. Petersen 
3916b90ebc3dSAkinobu Mita 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
3917b90ebc3dSAkinobu Mita 		map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
391844d92694SMartin K. Petersen 
3919cbf67842SDouglas Gilbert 		pr_info("%s: %lu provisioning blocks\n", __func__, map_size);
392044d92694SMartin K. Petersen 
392144d92694SMartin K. Petersen 		if (map_storep == NULL) {
3922cbf67842SDouglas Gilbert 			pr_err("%s: out of mem. (MAP)\n", __func__);
392344d92694SMartin K. Petersen 			ret = -ENOMEM;
392444d92694SMartin K. Petersen 			goto free_vm;
392544d92694SMartin K. Petersen 		}
392644d92694SMartin K. Petersen 
3927b90ebc3dSAkinobu Mita 		bitmap_zero(map_storep, map_size);
392844d92694SMartin K. Petersen 
392944d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
393044d92694SMartin K. Petersen 		if (scsi_debug_num_parts)
393144d92694SMartin K. Petersen 			map_region(0, 2);
393244d92694SMartin K. Petersen 	}
393344d92694SMartin K. Petersen 
39349b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
39359b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
3936cbf67842SDouglas Gilbert 		pr_warn("%s: root_device_register() error\n", __func__);
39379b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
39386ecaff7fSRandy Dunlap 		goto free_vm;
39396ecaff7fSRandy Dunlap 	}
39406ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
39416ecaff7fSRandy Dunlap 	if (ret < 0) {
3942cbf67842SDouglas Gilbert 		pr_warn("%s: bus_register error: %d\n", __func__, ret);
39436ecaff7fSRandy Dunlap 		goto dev_unreg;
39446ecaff7fSRandy Dunlap 	}
39456ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
39466ecaff7fSRandy Dunlap 	if (ret < 0) {
3947cbf67842SDouglas Gilbert 		pr_warn("%s: driver_register error: %d\n", __func__, ret);
39486ecaff7fSRandy Dunlap 		goto bus_unreg;
39496ecaff7fSRandy Dunlap 	}
39501da177e4SLinus Torvalds 
39511da177e4SLinus Torvalds 	host_to_add = scsi_debug_add_host;
39521da177e4SLinus Torvalds         scsi_debug_add_host = 0;
39531da177e4SLinus Torvalds 
39541da177e4SLinus Torvalds         for (k = 0; k < host_to_add; k++) {
39551da177e4SLinus Torvalds                 if (sdebug_add_adapter()) {
3956cbf67842SDouglas Gilbert 			pr_err("%s: sdebug_add_adapter failed k=%d\n",
3957cbf67842SDouglas Gilbert 				__func__, k);
39581da177e4SLinus Torvalds                         break;
39591da177e4SLinus Torvalds                 }
39601da177e4SLinus Torvalds         }
39611da177e4SLinus Torvalds 
39621da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
3963cbf67842SDouglas Gilbert 		pr_info("%s: built %d host(s)\n", __func__,
39641da177e4SLinus Torvalds 			scsi_debug_add_host);
39651da177e4SLinus Torvalds 	}
39661da177e4SLinus Torvalds 	return 0;
39676ecaff7fSRandy Dunlap 
39686ecaff7fSRandy Dunlap bus_unreg:
39696ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
39706ecaff7fSRandy Dunlap dev_unreg:
39719b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
39726ecaff7fSRandy Dunlap free_vm:
397344d92694SMartin K. Petersen 	if (map_storep)
397444d92694SMartin K. Petersen 		vfree(map_storep);
3975c6a44287SMartin K. Petersen 	if (dif_storep)
3976c6a44287SMartin K. Petersen 		vfree(dif_storep);
39776ecaff7fSRandy Dunlap 	vfree(fake_storep);
39786ecaff7fSRandy Dunlap 
39796ecaff7fSRandy Dunlap 	return ret;
39801da177e4SLinus Torvalds }
39811da177e4SLinus Torvalds 
39821da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
39831da177e4SLinus Torvalds {
39841da177e4SLinus Torvalds 	int k = scsi_debug_add_host;
39851da177e4SLinus Torvalds 
39861da177e4SLinus Torvalds 	stop_all_queued();
3987cbf67842SDouglas Gilbert 	free_all_queued();
39881da177e4SLinus Torvalds 	for (; k; k--)
39891da177e4SLinus Torvalds 		sdebug_remove_adapter();
39901da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
39911da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
39929b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
39931da177e4SLinus Torvalds 
3994c6a44287SMartin K. Petersen 	if (dif_storep)
3995c6a44287SMartin K. Petersen 		vfree(dif_storep);
3996c6a44287SMartin K. Petersen 
39971da177e4SLinus Torvalds 	vfree(fake_storep);
39981da177e4SLinus Torvalds }
39991da177e4SLinus Torvalds 
40001da177e4SLinus Torvalds device_initcall(scsi_debug_init);
40011da177e4SLinus Torvalds module_exit(scsi_debug_exit);
40021da177e4SLinus Torvalds 
40031da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev)
40041da177e4SLinus Torvalds {
40051da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
40061da177e4SLinus Torvalds 
40071da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
40081da177e4SLinus Torvalds         kfree(sdbg_host);
40091da177e4SLinus Torvalds }
40101da177e4SLinus Torvalds 
40111da177e4SLinus Torvalds static int sdebug_add_adapter(void)
40121da177e4SLinus Torvalds {
40131da177e4SLinus Torvalds 	int k, devs_per_host;
40141da177e4SLinus Torvalds         int error = 0;
40151da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
40168b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
40171da177e4SLinus Torvalds 
401824669f75SJes Sorensen         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
40191da177e4SLinus Torvalds         if (NULL == sdbg_host) {
40201da177e4SLinus Torvalds                 printk(KERN_ERR "%s: out of memory at line %d\n",
4021cadbd4a5SHarvey Harrison                        __func__, __LINE__);
40221da177e4SLinus Torvalds                 return -ENOMEM;
40231da177e4SLinus Torvalds         }
40241da177e4SLinus Torvalds 
40251da177e4SLinus Torvalds         INIT_LIST_HEAD(&sdbg_host->dev_info_list);
40261da177e4SLinus Torvalds 
40271da177e4SLinus Torvalds 	devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
40281da177e4SLinus Torvalds         for (k = 0; k < devs_per_host; k++) {
40295cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
40305cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
40311da177e4SLinus Torvalds                         printk(KERN_ERR "%s: out of memory at line %d\n",
4032cadbd4a5SHarvey Harrison                                __func__, __LINE__);
40331da177e4SLinus Torvalds                         error = -ENOMEM;
40341da177e4SLinus Torvalds 			goto clean;
40351da177e4SLinus Torvalds                 }
40361da177e4SLinus Torvalds         }
40371da177e4SLinus Torvalds 
40381da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
40391da177e4SLinus Torvalds         list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
40401da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
40411da177e4SLinus Torvalds 
40421da177e4SLinus Torvalds         sdbg_host->dev.bus = &pseudo_lld_bus;
40439b906779SNicholas Bellinger         sdbg_host->dev.parent = pseudo_primary;
40441da177e4SLinus Torvalds         sdbg_host->dev.release = &sdebug_release_adapter;
404571610f55SKay Sievers         dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
40461da177e4SLinus Torvalds 
40471da177e4SLinus Torvalds         error = device_register(&sdbg_host->dev);
40481da177e4SLinus Torvalds 
40491da177e4SLinus Torvalds         if (error)
40501da177e4SLinus Torvalds 		goto clean;
40511da177e4SLinus Torvalds 
40521da177e4SLinus Torvalds 	++scsi_debug_add_host;
40531da177e4SLinus Torvalds         return error;
40541da177e4SLinus Torvalds 
40551da177e4SLinus Torvalds clean:
40568b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
40578b40228fSFUJITA Tomonori 				 dev_list) {
40581da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
40591da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
40601da177e4SLinus Torvalds 	}
40611da177e4SLinus Torvalds 
40621da177e4SLinus Torvalds 	kfree(sdbg_host);
40631da177e4SLinus Torvalds         return error;
40641da177e4SLinus Torvalds }
40651da177e4SLinus Torvalds 
40661da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
40671da177e4SLinus Torvalds {
40681da177e4SLinus Torvalds         struct sdebug_host_info * sdbg_host = NULL;
40691da177e4SLinus Torvalds 
40701da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
40711da177e4SLinus Torvalds         if (!list_empty(&sdebug_host_list)) {
40721da177e4SLinus Torvalds                 sdbg_host = list_entry(sdebug_host_list.prev,
40731da177e4SLinus Torvalds                                        struct sdebug_host_info, host_list);
40741da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
40751da177e4SLinus Torvalds 	}
40761da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
40771da177e4SLinus Torvalds 
40781da177e4SLinus Torvalds 	if (!sdbg_host)
40791da177e4SLinus Torvalds 		return;
40801da177e4SLinus Torvalds 
40811da177e4SLinus Torvalds         device_unregister(&sdbg_host->dev);
40821da177e4SLinus Torvalds         --scsi_debug_add_host;
40831da177e4SLinus Torvalds }
40841da177e4SLinus Torvalds 
4085cbf67842SDouglas Gilbert static int
4086cbf67842SDouglas Gilbert scsi_debug_queuecommand(struct scsi_cmnd *SCpnt)
4087639db475SFUJITA Tomonori {
408801123ef4SDouglas Gilbert 	unsigned char *cmd = SCpnt->cmnd;
4089639db475SFUJITA Tomonori 	int len, k;
4090639db475SFUJITA Tomonori 	unsigned int num;
4091639db475SFUJITA Tomonori 	unsigned long long lba;
4092395cef03SMartin K. Petersen 	u32 ei_lba;
4093639db475SFUJITA Tomonori 	int errsts = 0;
4094639db475SFUJITA Tomonori 	int target = SCpnt->device->id;
4095639db475SFUJITA Tomonori 	struct sdebug_dev_info *devip = NULL;
4096639db475SFUJITA Tomonori 	int inj_recovered = 0;
4097639db475SFUJITA Tomonori 	int inj_transport = 0;
4098c6a44287SMartin K. Petersen 	int inj_dif = 0;
4099c6a44287SMartin K. Petersen 	int inj_dix = 0;
4100b57d7c01SChristoph Hellwig 	int inj_short = 0;
4101639db475SFUJITA Tomonori 	int delay_override = 0;
410244d92694SMartin K. Petersen 	int unmap = 0;
4103639db475SFUJITA Tomonori 
4104639db475SFUJITA Tomonori 	scsi_set_resid(SCpnt, 0);
4105cbf67842SDouglas Gilbert 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) &&
410601123ef4SDouglas Gilbert 	    !(SCSI_DEBUG_OPT_NO_CDB_NOISE & scsi_debug_opts)) {
4107cbf67842SDouglas Gilbert 		char b[120];
4108cbf67842SDouglas Gilbert 		int n;
4109639db475SFUJITA Tomonori 
4110cbf67842SDouglas Gilbert 		len = SCpnt->cmd_len;
4111cbf67842SDouglas Gilbert 		if (len > 32)
4112cbf67842SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
4113cbf67842SDouglas Gilbert 		else {
4114cbf67842SDouglas Gilbert 			for (k = 0, n = 0; k < len; ++k)
4115cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n, "%02x ",
4116cbf67842SDouglas Gilbert 					       (unsigned int)cmd[k]);
4117cbf67842SDouglas Gilbert 		}
4118cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s: cmd %s\n", my_name,
4119cbf67842SDouglas Gilbert 			    b);
4120639db475SFUJITA Tomonori 	}
4121639db475SFUJITA Tomonori 
4122639db475SFUJITA Tomonori 	if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
4123639db475SFUJITA Tomonori 	    (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
4124cbf67842SDouglas Gilbert 		return schedule_resp(SCpnt, NULL, DID_NO_CONNECT << 16, 0);
4125639db475SFUJITA Tomonori 	devip = devInfoReg(SCpnt->device);
4126639db475SFUJITA Tomonori 	if (NULL == devip)
4127cbf67842SDouglas Gilbert 		return schedule_resp(SCpnt, NULL, DID_NO_CONNECT << 16, 0);
4128639db475SFUJITA Tomonori 
4129639db475SFUJITA Tomonori 	if ((scsi_debug_every_nth != 0) &&
4130cbf67842SDouglas Gilbert 	    (atomic_inc_return(&sdebug_cmnd_count) >=
4131cbf67842SDouglas Gilbert 	     abs(scsi_debug_every_nth))) {
4132cbf67842SDouglas Gilbert 		atomic_set(&sdebug_cmnd_count, 0);
4133639db475SFUJITA Tomonori 		if (scsi_debug_every_nth < -1)
4134639db475SFUJITA Tomonori 			scsi_debug_every_nth = -1;
4135639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
4136639db475SFUJITA Tomonori 			return 0; /* ignore command causing timeout */
413718a4d0a2SMartin K. Petersen 		else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts &&
413818a4d0a2SMartin K. Petersen 			 scsi_medium_access_command(SCpnt))
413918a4d0a2SMartin K. Petersen 			return 0; /* time out reads and writes */
4140639db475SFUJITA Tomonori 		else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
4141639db475SFUJITA Tomonori 			inj_recovered = 1; /* to reads and writes below */
4142639db475SFUJITA Tomonori 		else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
4143639db475SFUJITA Tomonori 			inj_transport = 1; /* to reads and writes below */
4144c6a44287SMartin K. Petersen 		else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
4145c6a44287SMartin K. Petersen 			inj_dif = 1; /* to reads and writes below */
4146c6a44287SMartin K. Petersen 		else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
4147c6a44287SMartin K. Petersen 			inj_dix = 1; /* to reads and writes below */
4148b57d7c01SChristoph Hellwig 		else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & scsi_debug_opts)
4149b57d7c01SChristoph Hellwig 			inj_short = 1;
4150639db475SFUJITA Tomonori 	}
4151639db475SFUJITA Tomonori 
4152639db475SFUJITA Tomonori 	if (devip->wlun) {
4153639db475SFUJITA Tomonori 		switch (*cmd) {
4154639db475SFUJITA Tomonori 		case INQUIRY:
4155639db475SFUJITA Tomonori 		case REQUEST_SENSE:
4156639db475SFUJITA Tomonori 		case TEST_UNIT_READY:
4157639db475SFUJITA Tomonori 		case REPORT_LUNS:
4158639db475SFUJITA Tomonori 			break;  /* only allowable wlun commands */
4159639db475SFUJITA Tomonori 		default:
4160639db475SFUJITA Tomonori 			if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
4161639db475SFUJITA Tomonori 				printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
4162639db475SFUJITA Tomonori 				       "not supported for wlun\n", *cmd);
4163cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
4164639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
4165639db475SFUJITA Tomonori 			errsts = check_condition_result;
4166cbf67842SDouglas Gilbert 			return schedule_resp(SCpnt, devip, errsts, 0);
4167639db475SFUJITA Tomonori 		}
4168639db475SFUJITA Tomonori 	}
4169639db475SFUJITA Tomonori 
4170639db475SFUJITA Tomonori 	switch (*cmd) {
4171639db475SFUJITA Tomonori 	case INQUIRY:     /* mandatory, ignore unit attention */
4172639db475SFUJITA Tomonori 		delay_override = 1;
4173639db475SFUJITA Tomonori 		errsts = resp_inquiry(SCpnt, target, devip);
4174639db475SFUJITA Tomonori 		break;
4175639db475SFUJITA Tomonori 	case REQUEST_SENSE:	/* mandatory, ignore unit attention */
4176639db475SFUJITA Tomonori 		delay_override = 1;
4177639db475SFUJITA Tomonori 		errsts = resp_requests(SCpnt, devip);
4178639db475SFUJITA Tomonori 		break;
4179639db475SFUJITA Tomonori 	case REZERO_UNIT:	/* actually this is REWIND for SSC */
4180639db475SFUJITA Tomonori 	case START_STOP:
4181639db475SFUJITA Tomonori 		errsts = resp_start_stop(SCpnt, devip);
4182639db475SFUJITA Tomonori 		break;
4183639db475SFUJITA Tomonori 	case ALLOW_MEDIUM_REMOVAL:
4184cbf67842SDouglas Gilbert 		errsts = check_readiness(SCpnt, UAS_ONLY, devip);
4185639db475SFUJITA Tomonori 		if (errsts)
4186639db475SFUJITA Tomonori 			break;
4187639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
4188639db475SFUJITA Tomonori 			printk(KERN_INFO "scsi_debug: Medium removal %s\n",
4189639db475SFUJITA Tomonori 			       cmd[4] ? "inhibited" : "enabled");
4190639db475SFUJITA Tomonori 		break;
4191639db475SFUJITA Tomonori 	case SEND_DIAGNOSTIC:     /* mandatory */
4192cbf67842SDouglas Gilbert 		errsts = check_readiness(SCpnt, UAS_ONLY, devip);
4193639db475SFUJITA Tomonori 		break;
4194639db475SFUJITA Tomonori 	case TEST_UNIT_READY:     /* mandatory */
4195cbf67842SDouglas Gilbert 		/* delay_override = 1; */
4196cbf67842SDouglas Gilbert 		errsts = check_readiness(SCpnt, UAS_TUR, devip);
4197639db475SFUJITA Tomonori 		break;
4198639db475SFUJITA Tomonori 	case RESERVE:
4199cbf67842SDouglas Gilbert 		errsts = check_readiness(SCpnt, UAS_ONLY, devip);
4200639db475SFUJITA Tomonori 		break;
4201639db475SFUJITA Tomonori 	case RESERVE_10:
4202cbf67842SDouglas Gilbert 		errsts = check_readiness(SCpnt, UAS_ONLY, devip);
4203639db475SFUJITA Tomonori 		break;
4204639db475SFUJITA Tomonori 	case RELEASE:
4205cbf67842SDouglas Gilbert 		errsts = check_readiness(SCpnt, UAS_ONLY, devip);
4206639db475SFUJITA Tomonori 		break;
4207639db475SFUJITA Tomonori 	case RELEASE_10:
4208cbf67842SDouglas Gilbert 		errsts = check_readiness(SCpnt, UAS_ONLY, devip);
4209639db475SFUJITA Tomonori 		break;
4210639db475SFUJITA Tomonori 	case READ_CAPACITY:
4211639db475SFUJITA Tomonori 		errsts = resp_readcap(SCpnt, devip);
4212639db475SFUJITA Tomonori 		break;
4213639db475SFUJITA Tomonori 	case SERVICE_ACTION_IN:
421444d92694SMartin K. Petersen 		if (cmd[1] == SAI_READ_CAPACITY_16)
421544d92694SMartin K. Petersen 			errsts = resp_readcap16(SCpnt, devip);
421644d92694SMartin K. Petersen 		else if (cmd[1] == SAI_GET_LBA_STATUS) {
421744d92694SMartin K. Petersen 
42185b94e232SMartin K. Petersen 			if (scsi_debug_lbp() == 0) {
4219cbf67842SDouglas Gilbert 				mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
422044d92694SMartin K. Petersen 						INVALID_COMMAND_OPCODE, 0);
422144d92694SMartin K. Petersen 				errsts = check_condition_result;
422244d92694SMartin K. Petersen 			} else
422344d92694SMartin K. Petersen 				errsts = resp_get_lba_status(SCpnt, devip);
422444d92694SMartin K. Petersen 		} else {
4225cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
4226639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
4227639db475SFUJITA Tomonori 			errsts = check_condition_result;
4228639db475SFUJITA Tomonori 		}
4229639db475SFUJITA Tomonori 		break;
4230639db475SFUJITA Tomonori 	case MAINTENANCE_IN:
4231639db475SFUJITA Tomonori 		if (MI_REPORT_TARGET_PGS != cmd[1]) {
4232cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
4233639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
4234639db475SFUJITA Tomonori 			errsts = check_condition_result;
4235639db475SFUJITA Tomonori 			break;
4236639db475SFUJITA Tomonori 		}
4237639db475SFUJITA Tomonori 		errsts = resp_report_tgtpgs(SCpnt, devip);
4238639db475SFUJITA Tomonori 		break;
4239639db475SFUJITA Tomonori 	case READ_16:
4240639db475SFUJITA Tomonori 	case READ_12:
4241639db475SFUJITA Tomonori 	case READ_10:
4242395cef03SMartin K. Petersen 		/* READ{10,12,16} and DIF Type 2 are natural enemies */
4243395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
4244395cef03SMartin K. Petersen 		    cmd[1] & 0xe0) {
4245cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
4246395cef03SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
4247395cef03SMartin K. Petersen 			errsts = check_condition_result;
4248395cef03SMartin K. Petersen 			break;
4249395cef03SMartin K. Petersen 		}
4250395cef03SMartin K. Petersen 
4251395cef03SMartin K. Petersen 		if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
4252395cef03SMartin K. Petersen 		     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
4253395cef03SMartin K. Petersen 		    (cmd[1] & 0xe0) == 0)
4254395cef03SMartin K. Petersen 			printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
4255395cef03SMartin K. Petersen 
4256395cef03SMartin K. Petersen 		/* fall through */
4257639db475SFUJITA Tomonori 	case READ_6:
4258395cef03SMartin K. Petersen read:
4259cbf67842SDouglas Gilbert 		errsts = check_readiness(SCpnt, UAS_TUR, devip);
4260639db475SFUJITA Tomonori 		if (errsts)
4261639db475SFUJITA Tomonori 			break;
4262639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
4263639db475SFUJITA Tomonori 			break;
4264395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
4265b57d7c01SChristoph Hellwig 
4266b57d7c01SChristoph Hellwig 		if (inj_short)
4267b57d7c01SChristoph Hellwig 			num /= 2;
4268b57d7c01SChristoph Hellwig 
4269cbf67842SDouglas Gilbert 		errsts = resp_read(SCpnt, lba, num, ei_lba);
4270639db475SFUJITA Tomonori 		if (inj_recovered && (0 == errsts)) {
4271cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, RECOVERED_ERROR,
4272639db475SFUJITA Tomonori 					THRESHOLD_EXCEEDED, 0);
4273639db475SFUJITA Tomonori 			errsts = check_condition_result;
4274639db475SFUJITA Tomonori 		} else if (inj_transport && (0 == errsts)) {
4275cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, ABORTED_COMMAND,
4276639db475SFUJITA Tomonori 					TRANSPORT_PROBLEM, ACK_NAK_TO);
4277639db475SFUJITA Tomonori 			errsts = check_condition_result;
4278c6a44287SMartin K. Petersen 		} else if (inj_dif && (0 == errsts)) {
4279cbf67842SDouglas Gilbert 			/* Logical block guard check failed */
4280cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, ABORTED_COMMAND, 0x10, 1);
4281c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
4282c6a44287SMartin K. Petersen 		} else if (inj_dix && (0 == errsts)) {
4283cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, ILLEGAL_REQUEST, 0x10, 1);
4284c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
4285639db475SFUJITA Tomonori 		}
4286639db475SFUJITA Tomonori 		break;
4287639db475SFUJITA Tomonori 	case REPORT_LUNS:	/* mandatory, ignore unit attention */
4288639db475SFUJITA Tomonori 		delay_override = 1;
4289639db475SFUJITA Tomonori 		errsts = resp_report_luns(SCpnt, devip);
4290639db475SFUJITA Tomonori 		break;
4291639db475SFUJITA Tomonori 	case VERIFY:		/* 10 byte SBC-2 command */
4292cbf67842SDouglas Gilbert 		errsts = check_readiness(SCpnt, UAS_TUR, devip);
4293639db475SFUJITA Tomonori 		break;
4294639db475SFUJITA Tomonori 	case WRITE_16:
4295639db475SFUJITA Tomonori 	case WRITE_12:
4296639db475SFUJITA Tomonori 	case WRITE_10:
4297395cef03SMartin K. Petersen 		/* WRITE{10,12,16} and DIF Type 2 are natural enemies */
4298395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
4299395cef03SMartin K. Petersen 		    cmd[1] & 0xe0) {
4300cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
4301395cef03SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
4302395cef03SMartin K. Petersen 			errsts = check_condition_result;
4303395cef03SMartin K. Petersen 			break;
4304395cef03SMartin K. Petersen 		}
4305395cef03SMartin K. Petersen 
4306395cef03SMartin K. Petersen 		if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
4307395cef03SMartin K. Petersen 		     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
4308395cef03SMartin K. Petersen 		    (cmd[1] & 0xe0) == 0)
4309395cef03SMartin K. Petersen 			printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
4310395cef03SMartin K. Petersen 
4311395cef03SMartin K. Petersen 		/* fall through */
4312639db475SFUJITA Tomonori 	case WRITE_6:
4313395cef03SMartin K. Petersen write:
4314cbf67842SDouglas Gilbert 		errsts = check_readiness(SCpnt, UAS_TUR, devip);
4315639db475SFUJITA Tomonori 		if (errsts)
4316639db475SFUJITA Tomonori 			break;
4317639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
4318639db475SFUJITA Tomonori 			break;
4319395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
4320cbf67842SDouglas Gilbert 		errsts = resp_write(SCpnt, lba, num, ei_lba);
4321639db475SFUJITA Tomonori 		if (inj_recovered && (0 == errsts)) {
4322cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, RECOVERED_ERROR,
4323639db475SFUJITA Tomonori 					THRESHOLD_EXCEEDED, 0);
4324639db475SFUJITA Tomonori 			errsts = check_condition_result;
4325c6a44287SMartin K. Petersen 		} else if (inj_dif && (0 == errsts)) {
4326cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, ABORTED_COMMAND, 0x10, 1);
4327c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
4328c6a44287SMartin K. Petersen 		} else if (inj_dix && (0 == errsts)) {
4329cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, ILLEGAL_REQUEST, 0x10, 1);
4330c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
4331639db475SFUJITA Tomonori 		}
4332639db475SFUJITA Tomonori 		break;
433344d92694SMartin K. Petersen 	case WRITE_SAME_16:
43345b94e232SMartin K. Petersen 	case WRITE_SAME:
43356014759cSMartin K. Petersen 		if (cmd[1] & 0x8) {
43365b94e232SMartin K. Petersen 			if ((*cmd == WRITE_SAME_16 && scsi_debug_lbpws == 0) ||
43375b94e232SMartin K. Petersen 			    (*cmd == WRITE_SAME && scsi_debug_lbpws10 == 0)) {
4338cbf67842SDouglas Gilbert 				mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
43396014759cSMartin K. Petersen 						INVALID_FIELD_IN_CDB, 0);
43406014759cSMartin K. Petersen 				errsts = check_condition_result;
43416014759cSMartin K. Petersen 			} else
434244d92694SMartin K. Petersen 				unmap = 1;
43436014759cSMartin K. Petersen 		}
43446014759cSMartin K. Petersen 		if (errsts)
43456014759cSMartin K. Petersen 			break;
4346cbf67842SDouglas Gilbert 		errsts = check_readiness(SCpnt, UAS_TUR, devip);
434744d92694SMartin K. Petersen 		if (errsts)
434844d92694SMartin K. Petersen 			break;
4349cbf67842SDouglas Gilbert 		if (scsi_debug_fake_rw)
4350cbf67842SDouglas Gilbert 			break;
435144d92694SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
4352cbf67842SDouglas Gilbert 		errsts = resp_write_same(SCpnt, lba, num, ei_lba, unmap);
435344d92694SMartin K. Petersen 		break;
435444d92694SMartin K. Petersen 	case UNMAP:
4355cbf67842SDouglas Gilbert 		errsts = check_readiness(SCpnt, UAS_TUR, devip);
435644d92694SMartin K. Petersen 		if (errsts)
435744d92694SMartin K. Petersen 			break;
4358cbf67842SDouglas Gilbert 		if (scsi_debug_fake_rw)
4359cbf67842SDouglas Gilbert 			break;
436044d92694SMartin K. Petersen 
43615b94e232SMartin K. Petersen 		if (scsi_debug_unmap_max_desc == 0 || scsi_debug_lbpu == 0) {
4362cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
436344d92694SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
436444d92694SMartin K. Petersen 			errsts = check_condition_result;
436544d92694SMartin K. Petersen 		} else
436644d92694SMartin K. Petersen 			errsts = resp_unmap(SCpnt, devip);
436744d92694SMartin K. Petersen 		break;
4368639db475SFUJITA Tomonori 	case MODE_SENSE:
4369639db475SFUJITA Tomonori 	case MODE_SENSE_10:
4370639db475SFUJITA Tomonori 		errsts = resp_mode_sense(SCpnt, target, devip);
4371639db475SFUJITA Tomonori 		break;
4372639db475SFUJITA Tomonori 	case MODE_SELECT:
4373639db475SFUJITA Tomonori 		errsts = resp_mode_select(SCpnt, 1, devip);
4374639db475SFUJITA Tomonori 		break;
4375639db475SFUJITA Tomonori 	case MODE_SELECT_10:
4376639db475SFUJITA Tomonori 		errsts = resp_mode_select(SCpnt, 0, devip);
4377639db475SFUJITA Tomonori 		break;
4378639db475SFUJITA Tomonori 	case LOG_SENSE:
4379639db475SFUJITA Tomonori 		errsts = resp_log_sense(SCpnt, devip);
4380639db475SFUJITA Tomonori 		break;
4381639db475SFUJITA Tomonori 	case SYNCHRONIZE_CACHE:
4382639db475SFUJITA Tomonori 		delay_override = 1;
4383cbf67842SDouglas Gilbert 		errsts = check_readiness(SCpnt, UAS_TUR, devip);
4384639db475SFUJITA Tomonori 		break;
4385639db475SFUJITA Tomonori 	case WRITE_BUFFER:
4386cbf67842SDouglas Gilbert 		errsts = check_readiness(SCpnt, UAS_ONLY, devip);
4387639db475SFUJITA Tomonori 		break;
4388639db475SFUJITA Tomonori 	case XDWRITEREAD_10:
4389639db475SFUJITA Tomonori 		if (!scsi_bidi_cmnd(SCpnt)) {
4390cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
4391639db475SFUJITA Tomonori 					INVALID_FIELD_IN_CDB, 0);
4392639db475SFUJITA Tomonori 			errsts = check_condition_result;
4393639db475SFUJITA Tomonori 			break;
4394639db475SFUJITA Tomonori 		}
4395639db475SFUJITA Tomonori 
4396cbf67842SDouglas Gilbert 		errsts = check_readiness(SCpnt, UAS_TUR, devip);
4397639db475SFUJITA Tomonori 		if (errsts)
4398639db475SFUJITA Tomonori 			break;
4399639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
4400639db475SFUJITA Tomonori 			break;
4401395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
4402cbf67842SDouglas Gilbert 		errsts = resp_read(SCpnt, lba, num, ei_lba);
4403639db475SFUJITA Tomonori 		if (errsts)
4404639db475SFUJITA Tomonori 			break;
4405cbf67842SDouglas Gilbert 		errsts = resp_write(SCpnt, lba, num, ei_lba);
4406639db475SFUJITA Tomonori 		if (errsts)
4407639db475SFUJITA Tomonori 			break;
4408639db475SFUJITA Tomonori 		errsts = resp_xdwriteread(SCpnt, lba, num, devip);
4409639db475SFUJITA Tomonori 		break;
4410395cef03SMartin K. Petersen 	case VARIABLE_LENGTH_CMD:
4411395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
4412395cef03SMartin K. Petersen 
4413395cef03SMartin K. Petersen 			if ((cmd[10] & 0xe0) == 0)
4414395cef03SMartin K. Petersen 				printk(KERN_ERR
4415395cef03SMartin K. Petersen 				       "Unprotected RD/WR to DIF device\n");
4416395cef03SMartin K. Petersen 
4417395cef03SMartin K. Petersen 			if (cmd[9] == READ_32) {
4418395cef03SMartin K. Petersen 				BUG_ON(SCpnt->cmd_len < 32);
4419395cef03SMartin K. Petersen 				goto read;
4420395cef03SMartin K. Petersen 			}
4421395cef03SMartin K. Petersen 
4422395cef03SMartin K. Petersen 			if (cmd[9] == WRITE_32) {
4423395cef03SMartin K. Petersen 				BUG_ON(SCpnt->cmd_len < 32);
4424395cef03SMartin K. Petersen 				goto write;
4425395cef03SMartin K. Petersen 			}
4426395cef03SMartin K. Petersen 		}
4427395cef03SMartin K. Petersen 
4428cbf67842SDouglas Gilbert 		mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
4429395cef03SMartin K. Petersen 				INVALID_FIELD_IN_CDB, 0);
4430395cef03SMartin K. Petersen 		errsts = check_condition_result;
4431395cef03SMartin K. Petersen 		break;
4432cbf67842SDouglas Gilbert 	case 0x85:
4433cbf67842SDouglas Gilbert 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
4434cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
4435cbf67842SDouglas Gilbert 			"%s: ATA PASS-THROUGH(16) not supported\n", my_name);
4436cbf67842SDouglas Gilbert 		mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
4437cbf67842SDouglas Gilbert 				INVALID_OPCODE, 0);
4438cbf67842SDouglas Gilbert 		errsts = check_condition_result;
4439cbf67842SDouglas Gilbert 		break;
4440639db475SFUJITA Tomonori 	default:
4441639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
4442cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
4443cbf67842SDouglas Gilbert 				    "%s: Opcode: 0x%x not supported\n",
4444cbf67842SDouglas Gilbert 				    my_name, *cmd);
4445cbf67842SDouglas Gilbert 		errsts = check_readiness(SCpnt, UAS_ONLY, devip);
4446639db475SFUJITA Tomonori 		if (errsts)
4447639db475SFUJITA Tomonori 			break;	/* Unit attention takes precedence */
4448cbf67842SDouglas Gilbert 		mk_sense_buffer(SCpnt, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
4449639db475SFUJITA Tomonori 		errsts = check_condition_result;
4450639db475SFUJITA Tomonori 		break;
4451639db475SFUJITA Tomonori 	}
4452cbf67842SDouglas Gilbert 	return schedule_resp(SCpnt, devip, errsts,
4453639db475SFUJITA Tomonori 			     (delay_override ? 0 : scsi_debug_delay));
4454639db475SFUJITA Tomonori }
4455639db475SFUJITA Tomonori 
4456cbf67842SDouglas Gilbert static int
4457cbf67842SDouglas Gilbert sdebug_queuecommand_lock_or_not(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
4458cbf67842SDouglas Gilbert {
4459cbf67842SDouglas Gilbert 	if (scsi_debug_host_lock) {
4460cbf67842SDouglas Gilbert 		unsigned long iflags;
4461cbf67842SDouglas Gilbert 		int rc;
4462cbf67842SDouglas Gilbert 
4463cbf67842SDouglas Gilbert 		spin_lock_irqsave(shost->host_lock, iflags);
4464cbf67842SDouglas Gilbert 		rc = scsi_debug_queuecommand(cmd);
4465cbf67842SDouglas Gilbert 		spin_unlock_irqrestore(shost->host_lock, iflags);
4466cbf67842SDouglas Gilbert 		return rc;
4467cbf67842SDouglas Gilbert 	} else
4468cbf67842SDouglas Gilbert 		return scsi_debug_queuecommand(cmd);
4469cbf67842SDouglas Gilbert }
4470cbf67842SDouglas Gilbert 
4471cbf67842SDouglas Gilbert static int
4472cbf67842SDouglas Gilbert sdebug_change_qdepth(struct scsi_device *sdev, int qdepth, int reason)
4473cbf67842SDouglas Gilbert {
4474cbf67842SDouglas Gilbert 	int num_in_q = 0;
4475cbf67842SDouglas Gilbert 	unsigned long iflags;
4476cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4477cbf67842SDouglas Gilbert 
4478cbf67842SDouglas Gilbert 	spin_lock_irqsave(&queued_arr_lock, iflags);
4479cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
4480cbf67842SDouglas Gilbert 	if (NULL == devip) {
4481cbf67842SDouglas Gilbert 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
4482cbf67842SDouglas Gilbert 		return	-ENODEV;
4483cbf67842SDouglas Gilbert 	}
4484cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
4485cbf67842SDouglas Gilbert 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
4486c40ecc12SChristoph Hellwig 
4487cbf67842SDouglas Gilbert 	if (qdepth < 1)
4488cbf67842SDouglas Gilbert 		qdepth = 1;
4489cbf67842SDouglas Gilbert 	/* allow to exceed max host queued_arr elements for testing */
4490cbf67842SDouglas Gilbert 	if (qdepth > SCSI_DEBUG_CANQUEUE + 10)
4491cbf67842SDouglas Gilbert 		qdepth = SCSI_DEBUG_CANQUEUE + 10;
4492c8b09f6fSChristoph Hellwig 	scsi_adjust_queue_depth(sdev, qdepth);
4493cbf67842SDouglas Gilbert 
4494c40ecc12SChristoph Hellwig 	if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) {
4495cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev,
4496c40ecc12SChristoph Hellwig 			    "%s: qdepth=%d, num_in_q=%d\n",
4497c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
4498cbf67842SDouglas Gilbert 	}
4499cbf67842SDouglas Gilbert 	return sdev->queue_depth;
4500cbf67842SDouglas Gilbert }
4501cbf67842SDouglas Gilbert 
4502cbf67842SDouglas Gilbert static int
4503cbf67842SDouglas Gilbert sdebug_change_qtype(struct scsi_device *sdev, int qtype)
4504cbf67842SDouglas Gilbert {
4505a62182f3SChristoph Hellwig 	qtype = scsi_change_queue_type(sdev, qtype);
4506cbf67842SDouglas Gilbert 	if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) {
4507cbf67842SDouglas Gilbert 		const char *cp;
4508cbf67842SDouglas Gilbert 
4509cbf67842SDouglas Gilbert 		switch (qtype) {
4510cbf67842SDouglas Gilbert 		case 0:
4511cbf67842SDouglas Gilbert 			cp = "untagged";
4512cbf67842SDouglas Gilbert 			break;
4513cbf67842SDouglas Gilbert 		case MSG_SIMPLE_TAG:
4514cbf67842SDouglas Gilbert 			cp = "simple tags";
4515cbf67842SDouglas Gilbert 			break;
4516cbf67842SDouglas Gilbert 		case MSG_ORDERED_TAG:
4517cbf67842SDouglas Gilbert 			cp = "ordered tags";
4518cbf67842SDouglas Gilbert 			break;
4519cbf67842SDouglas Gilbert 		default:
4520cbf67842SDouglas Gilbert 			cp = "unknown";
4521cbf67842SDouglas Gilbert 			break;
4522cbf67842SDouglas Gilbert 		}
4523cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev, "%s: to %s\n", __func__, cp);
4524cbf67842SDouglas Gilbert 	}
4525cbf67842SDouglas Gilbert 	return qtype;
4526cbf67842SDouglas Gilbert }
4527f281233dSJeff Garzik 
45289e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
4529c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
4530c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
45319e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
45329e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
45339e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
45349e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
45359e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
45369e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
45379e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
4538cbf67842SDouglas Gilbert 	.queuecommand =		sdebug_queuecommand_lock_or_not,
4539cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
4540cbf67842SDouglas Gilbert 	.change_queue_type =	sdebug_change_qtype,
45419e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
45429e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
4543cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
4544cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
45459e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
45469e603ca0SFUJITA Tomonori 	.can_queue =		SCSI_DEBUG_CANQUEUE,
45479e603ca0SFUJITA Tomonori 	.this_id =		7,
45486bb5e6e7SAkinobu Mita 	.sg_tablesize =		SCSI_MAX_SG_CHAIN_SEGMENTS,
4549cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
45506bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
45519e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
45529e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
4553c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
45549e603ca0SFUJITA Tomonori };
45559e603ca0SFUJITA Tomonori 
45561da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev)
45571da177e4SLinus Torvalds {
45581da177e4SLinus Torvalds         int error = 0;
45591da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
45601da177e4SLinus Torvalds         struct Scsi_Host *hpnt;
4561c6a44287SMartin K. Petersen 	int host_prot;
45621da177e4SLinus Torvalds 
45631da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
45641da177e4SLinus Torvalds 
456578d4e5a0SDouglas Gilbert 	sdebug_driver_template.can_queue = scsi_debug_max_queue;
45660759c666SAkinobu Mita 	if (scsi_debug_clustering)
45670759c666SAkinobu Mita 		sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
45681da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
45691da177e4SLinus Torvalds 	if (NULL == hpnt) {
457017c9ff52SFinn Thain 		pr_err("%s: scsi_host_alloc failed\n", __func__);
45711da177e4SLinus Torvalds 		error = -ENODEV;
45721da177e4SLinus Torvalds 		return error;
45731da177e4SLinus Torvalds 	}
45741da177e4SLinus Torvalds 
45751da177e4SLinus Torvalds         sdbg_host->shost = hpnt;
45761da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
45771da177e4SLinus Torvalds 	if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
45781da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts + 1;
45791da177e4SLinus Torvalds 	else
45801da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts;
4581c65b1445SDouglas Gilbert 	hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;	/* = scsi_debug_max_luns; */
45821da177e4SLinus Torvalds 
4583c6a44287SMartin K. Petersen 	host_prot = 0;
4584c6a44287SMartin K. Petersen 
4585c6a44287SMartin K. Petersen 	switch (scsi_debug_dif) {
4586c6a44287SMartin K. Petersen 
4587c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
4588c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE1_PROTECTION;
4589c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
4590c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE1_PROTECTION;
4591c6a44287SMartin K. Petersen 		break;
4592c6a44287SMartin K. Petersen 
4593c6a44287SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
4594c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE2_PROTECTION;
4595c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
4596c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE2_PROTECTION;
4597c6a44287SMartin K. Petersen 		break;
4598c6a44287SMartin K. Petersen 
4599c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
4600c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE3_PROTECTION;
4601c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
4602c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE3_PROTECTION;
4603c6a44287SMartin K. Petersen 		break;
4604c6a44287SMartin K. Petersen 
4605c6a44287SMartin K. Petersen 	default:
4606c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
4607c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE0_PROTECTION;
4608c6a44287SMartin K. Petersen 		break;
4609c6a44287SMartin K. Petersen 	}
4610c6a44287SMartin K. Petersen 
4611c6a44287SMartin K. Petersen 	scsi_host_set_prot(hpnt, host_prot);
4612c6a44287SMartin K. Petersen 
4613c6a44287SMartin K. Petersen 	printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
4614c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
4615c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
4616c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
4617c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
4618c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
4619c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
4620c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
4621c6a44287SMartin K. Petersen 
4622c6a44287SMartin K. Petersen 	if (scsi_debug_guard == 1)
4623c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
4624c6a44287SMartin K. Petersen 	else
4625c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
4626c6a44287SMartin K. Petersen 
46271da177e4SLinus Torvalds         error = scsi_add_host(hpnt, &sdbg_host->dev);
46281da177e4SLinus Torvalds         if (error) {
4629cadbd4a5SHarvey Harrison                 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
46301da177e4SLinus Torvalds                 error = -ENODEV;
46311da177e4SLinus Torvalds 		scsi_host_put(hpnt);
46321da177e4SLinus Torvalds         } else
46331da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
46341da177e4SLinus Torvalds 
46351da177e4SLinus Torvalds 	return error;
46361da177e4SLinus Torvalds }
46371da177e4SLinus Torvalds 
46381da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev)
46391da177e4SLinus Torvalds {
46401da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
46418b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
46421da177e4SLinus Torvalds 
46431da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
46441da177e4SLinus Torvalds 
46451da177e4SLinus Torvalds 	if (!sdbg_host) {
46461da177e4SLinus Torvalds 		printk(KERN_ERR "%s: Unable to locate host info\n",
4647cadbd4a5SHarvey Harrison 		       __func__);
46481da177e4SLinus Torvalds 		return -ENODEV;
46491da177e4SLinus Torvalds 	}
46501da177e4SLinus Torvalds 
46511da177e4SLinus Torvalds         scsi_remove_host(sdbg_host->shost);
46521da177e4SLinus Torvalds 
46538b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
46548b40228fSFUJITA Tomonori 				 dev_list) {
46551da177e4SLinus Torvalds                 list_del(&sdbg_devinfo->dev_list);
46561da177e4SLinus Torvalds                 kfree(sdbg_devinfo);
46571da177e4SLinus Torvalds         }
46581da177e4SLinus Torvalds 
46591da177e4SLinus Torvalds         scsi_host_put(sdbg_host->shost);
46601da177e4SLinus Torvalds         return 0;
46611da177e4SLinus Torvalds }
46621da177e4SLinus Torvalds 
46638dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
46648dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
46651da177e4SLinus Torvalds {
46668dea0d02SFUJITA Tomonori 	return 1;
46678dea0d02SFUJITA Tomonori }
46681da177e4SLinus Torvalds 
46698dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
46708dea0d02SFUJITA Tomonori 	.name = "pseudo",
46718dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
46728dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
46738dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
467482069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
46758dea0d02SFUJITA Tomonori };
4676