xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision a4517511)
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>
45c6a44287SMartin K. Petersen 
46c6a44287SMartin K. Petersen #include <net/checksum.h>
479ff26eefSFUJITA Tomonori 
4844d92694SMartin K. Petersen #include <asm/unaligned.h>
4944d92694SMartin K. Petersen 
509ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
519ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
529ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
531da177e4SLinus Torvalds #include <scsi/scsi_host.h>
541da177e4SLinus Torvalds #include <scsi/scsicam.h>
55a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
56395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
571da177e4SLinus Torvalds 
58c6a44287SMartin K. Petersen #include "sd.h"
591da177e4SLinus Torvalds #include "scsi_logging.h"
601da177e4SLinus Torvalds 
6178d4e5a0SDouglas Gilbert #define SCSI_DEBUG_VERSION "1.82"
6278d4e5a0SDouglas Gilbert static const char * scsi_debug_version_date = "20100324";
631da177e4SLinus Torvalds 
646f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
65c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
66c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
671da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
68c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
691da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
701da177e4SLinus Torvalds #define ADDR_OUT_OF_RANGE 0x21
71395cef03SMartin K. Petersen #define INVALID_COMMAND_OPCODE 0x20
721da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
73c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
741da177e4SLinus Torvalds #define POWERON_RESET 0x29
751da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
766f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
77c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
78c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
791da177e4SLinus Torvalds 
806f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
816f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
826f3cbf55SDouglas Gilbert 
831da177e4SLinus Torvalds #define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds /* Default values for driver parameters */
861da177e4SLinus Torvalds #define DEF_NUM_HOST   1
871da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
881da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
891da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
901da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
911da177e4SLinus Torvalds  */
925b94e232SMartin K. Petersen #define DEF_ATO 1
931da177e4SLinus Torvalds #define DEF_DELAY   1
941da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
955b94e232SMartin K. Petersen #define DEF_DIF 0
965b94e232SMartin K. Petersen #define DEF_DIX 0
975b94e232SMartin K. Petersen #define DEF_D_SENSE   0
981da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
995b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1005b94e232SMartin K. Petersen #define DEF_GUARD 0
1015b94e232SMartin K. Petersen #define DEF_LBPU 0
1025b94e232SMartin K. Petersen #define DEF_LBPWS 0
1035b94e232SMartin K. Petersen #define DEF_LBPWS10 0
104be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1055b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
1065b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1071da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1081da177e4SLinus Torvalds #define DEF_OPTS   0
109e308b3d1SMartin K. Petersen #define DEF_OPT_BLKS 64
1105b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
1115b94e232SMartin K. Petersen #define DEF_PTYPE   0
112d986788bSMartin Pitt #define DEF_REMOVABLE false
1135b94e232SMartin K. Petersen #define DEF_SCSI_LEVEL   5    /* INQUIRY, byte2 [5->SPC-3] */
1145b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1155b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1165b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1176014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1186014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1195b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1205b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1215b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
1221da177e4SLinus Torvalds 
1231da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */
1241da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE   1
1251da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR   2
1261da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT   4
1271da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR   8
1286f3cbf55SDouglas Gilbert #define SCSI_DEBUG_OPT_TRANSPORT_ERR   16
129c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIF_ERR   32
130c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIX_ERR   64
13118a4d0a2SMartin K. Petersen #define SCSI_DEBUG_OPT_MAC_TIMEOUT  128
1321da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
1331da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1341da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1351da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1366f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1376f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1381da177e4SLinus Torvalds  *
1391da177e4SLinus Torvalds  * When "every_nth" < 0 then after "- every_nth" commands:
1401da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1411da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1421da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1436f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1446f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1451da177e4SLinus Torvalds  * This will continue until some other action occurs (e.g. the user
1461da177e4SLinus Torvalds  * writing a new value (other than -1 or 1) to every_nth via sysfs).
1471da177e4SLinus Torvalds  */
1481da177e4SLinus Torvalds 
1491da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
1501da177e4SLinus Torvalds  * sector on read commands: */
1511da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
15232f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
1551da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
1561da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
157c65b1445SDouglas Gilbert #define SAM2_WLUN_REPORT_LUNS 0xc101
1581da177e4SLinus Torvalds 
15978d4e5a0SDouglas Gilbert /* Can queue up to this number of commands. Typically commands that
16078d4e5a0SDouglas Gilbert  * that have a non-zero delay are queued. */
16178d4e5a0SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE  255
16278d4e5a0SDouglas Gilbert 
1631da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST;
1645b94e232SMartin K. Petersen static int scsi_debug_ato = DEF_ATO;
1651da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY;
1661da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
1675b94e232SMartin K. Petersen static int scsi_debug_dif = DEF_DIF;
1685b94e232SMartin K. Petersen static int scsi_debug_dix = DEF_DIX;
1695b94e232SMartin K. Petersen static int scsi_debug_dsense = DEF_D_SENSE;
1701da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH;
1715b94e232SMartin K. Petersen static int scsi_debug_fake_rw = DEF_FAKE_RW;
1725b94e232SMartin K. Petersen static int scsi_debug_guard = DEF_GUARD;
1735b94e232SMartin K. Petersen static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
1741da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS;
17578d4e5a0SDouglas Gilbert static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE;
176c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
1775b94e232SMartin K. Petersen static int scsi_debug_no_uld = 0;
1785b94e232SMartin K. Petersen static int scsi_debug_num_parts = DEF_NUM_PARTS;
1795b94e232SMartin K. Petersen static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
180e308b3d1SMartin K. Petersen static int scsi_debug_opt_blks = DEF_OPT_BLKS;
1815b94e232SMartin K. Petersen static int scsi_debug_opts = DEF_OPTS;
1825b94e232SMartin K. Petersen static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
1835b94e232SMartin K. Petersen static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
1845b94e232SMartin K. Petersen static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
1855b94e232SMartin K. Petersen static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
1865b94e232SMartin K. Petersen static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
1875b94e232SMartin K. Petersen static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
1885b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpu = DEF_LBPU;
1895b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws = DEF_LBPWS;
1905b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10;
191be1dd78dSEric Sandeen static unsigned int scsi_debug_lbprz = DEF_LBPRZ;
1926014759cSMartin K. Petersen static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
1935b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
1945b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
1955b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
1965b94e232SMartin K. Petersen static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH;
197d986788bSMartin Pitt static bool scsi_debug_removable = DEF_REMOVABLE;
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds static int scsi_debug_cmnd_count = 0;
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds #define DEV_READONLY(TGT)      (0)
2021da177e4SLinus Torvalds 
203c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
2041da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
2051da177e4SLinus Torvalds 
2061da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
2071da177e4SLinus Torvalds    may still need them */
2081da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
2091da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
2101da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4
2131da177e4SLinus Torvalds 
2141da177e4SLinus Torvalds #define SDEBUG_SENSE_LEN 32
2151da177e4SLinus Torvalds 
216395cef03SMartin K. Petersen #define SCSI_DEBUG_MAX_CMD_LEN 32
2179e603ca0SFUJITA Tomonori 
2185b94e232SMartin K. Petersen static unsigned int scsi_debug_lbp(void)
2195b94e232SMartin K. Petersen {
2205b94e232SMartin K. Petersen 	return scsi_debug_lbpu | scsi_debug_lbpws | scsi_debug_lbpws10;
2215b94e232SMartin K. Petersen }
2225b94e232SMartin K. Petersen 
2231da177e4SLinus Torvalds struct sdebug_dev_info {
2241da177e4SLinus Torvalds 	struct list_head dev_list;
2251da177e4SLinus Torvalds 	unsigned char sense_buff[SDEBUG_SENSE_LEN];	/* weak nexus */
2261da177e4SLinus Torvalds 	unsigned int channel;
2271da177e4SLinus Torvalds 	unsigned int target;
2281da177e4SLinus Torvalds 	unsigned int lun;
2291da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
230c65b1445SDouglas Gilbert 	unsigned int wlun;
2311da177e4SLinus Torvalds 	char reset;
232c65b1445SDouglas Gilbert 	char stopped;
2331da177e4SLinus Torvalds 	char used;
2341da177e4SLinus Torvalds };
2351da177e4SLinus Torvalds 
2361da177e4SLinus Torvalds struct sdebug_host_info {
2371da177e4SLinus Torvalds 	struct list_head host_list;
2381da177e4SLinus Torvalds 	struct Scsi_Host *shost;
2391da177e4SLinus Torvalds 	struct device dev;
2401da177e4SLinus Torvalds 	struct list_head dev_info_list;
2411da177e4SLinus Torvalds };
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds #define to_sdebug_host(d)	\
2441da177e4SLinus Torvalds 	container_of(d, struct sdebug_host_info, dev)
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
2471da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds typedef void (* done_funct_t) (struct scsi_cmnd *);
2501da177e4SLinus Torvalds 
2511da177e4SLinus Torvalds struct sdebug_queued_cmd {
2521da177e4SLinus Torvalds 	int in_use;
2531da177e4SLinus Torvalds 	struct timer_list cmnd_timer;
2541da177e4SLinus Torvalds 	done_funct_t done_funct;
2551da177e4SLinus Torvalds 	struct scsi_cmnd * a_cmnd;
2561da177e4SLinus Torvalds 	int scsi_result;
2571da177e4SLinus Torvalds };
2581da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
2591da177e4SLinus Torvalds 
2601da177e4SLinus Torvalds static unsigned char * fake_storep;	/* ramdisk storage */
261c6a44287SMartin K. Petersen static unsigned char *dif_storep;	/* protection info */
26244d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
2631da177e4SLinus Torvalds 
26444d92694SMartin K. Petersen static unsigned long map_size;
2651da177e4SLinus Torvalds static int num_aborts = 0;
2661da177e4SLinus Torvalds static int num_dev_resets = 0;
2671da177e4SLinus Torvalds static int num_bus_resets = 0;
2681da177e4SLinus Torvalds static int num_host_resets = 0;
269c6a44287SMartin K. Petersen static int dix_writes;
270c6a44287SMartin K. Petersen static int dix_reads;
271c6a44287SMartin K. Petersen static int dif_errors;
2721da177e4SLinus Torvalds 
2731da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock);
2741da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds static char sdebug_proc_name[] = "scsi_debug";
2771da177e4SLinus Torvalds 
2781da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
2791da177e4SLinus Torvalds 
280c6a44287SMartin K. Petersen static inline sector_t dif_offset(sector_t sector)
281c6a44287SMartin K. Petersen {
282c6a44287SMartin K. Petersen 	return sector << 3;
283c6a44287SMartin K. Petersen }
284c6a44287SMartin K. Petersen 
2851da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
2861da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
2871da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
2881da177e4SLinus Torvalds };
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds static const int check_condition_result =
2911da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
2921da177e4SLinus Torvalds 
293c6a44287SMartin K. Petersen static const int illegal_condition_result =
294c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
295c6a44287SMartin K. Petersen 
296c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
297c65b1445SDouglas Gilbert 				    0, 0, 0x2, 0x4b};
298c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
299c65b1445SDouglas Gilbert 			           0, 0, 0x0, 0x0};
300c65b1445SDouglas Gilbert 
3011da177e4SLinus Torvalds static int sdebug_add_adapter(void);
3021da177e4SLinus Torvalds static void sdebug_remove_adapter(void);
3031da177e4SLinus Torvalds 
3048dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
3058dea0d02SFUJITA Tomonori {
3068dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
3078dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
3088dea0d02SFUJITA Tomonori 
3098dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
3108dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3118dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
3128dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
3138dea0d02SFUJITA Tomonori 		    (scsi_debug_num_tgts > hpnt->this_id))
3148dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts + 1;
3158dea0d02SFUJITA Tomonori 		else
3168dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts;
3178dea0d02SFUJITA Tomonori 		/* scsi_debug_max_luns; */
3188dea0d02SFUJITA Tomonori 		hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
3198dea0d02SFUJITA Tomonori 	}
3208dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
3218dea0d02SFUJITA Tomonori }
3228dea0d02SFUJITA Tomonori 
3238dea0d02SFUJITA Tomonori static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
3248dea0d02SFUJITA Tomonori 			    int asc, int asq)
3258dea0d02SFUJITA Tomonori {
3268dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
3278dea0d02SFUJITA Tomonori 
3288dea0d02SFUJITA Tomonori 	sbuff = devip->sense_buff;
3298dea0d02SFUJITA Tomonori 	memset(sbuff, 0, SDEBUG_SENSE_LEN);
3308dea0d02SFUJITA Tomonori 
3318dea0d02SFUJITA Tomonori 	scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
3328dea0d02SFUJITA Tomonori 
3338dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3348dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug:    [sense_key,asc,ascq]: "
3358dea0d02SFUJITA Tomonori 		      "[0x%x,0x%x,0x%x]\n", key, asc, asq);
3368dea0d02SFUJITA Tomonori }
3371da177e4SLinus Torvalds 
3383de9f944SFUJITA Tomonori static void get_data_transfer_info(unsigned char *cmd,
339395cef03SMartin K. Petersen 				   unsigned long long *lba, unsigned int *num,
340395cef03SMartin K. Petersen 				   u32 *ei_lba)
3413de9f944SFUJITA Tomonori {
342395cef03SMartin K. Petersen 	*ei_lba = 0;
343395cef03SMartin K. Petersen 
3443de9f944SFUJITA Tomonori 	switch (*cmd) {
345395cef03SMartin K. Petersen 	case VARIABLE_LENGTH_CMD:
346395cef03SMartin K. Petersen 		*lba = (u64)cmd[19] | (u64)cmd[18] << 8 |
347395cef03SMartin K. Petersen 			(u64)cmd[17] << 16 | (u64)cmd[16] << 24 |
348395cef03SMartin K. Petersen 			(u64)cmd[15] << 32 | (u64)cmd[14] << 40 |
349395cef03SMartin K. Petersen 			(u64)cmd[13] << 48 | (u64)cmd[12] << 56;
350395cef03SMartin K. Petersen 
351395cef03SMartin K. Petersen 		*ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 |
352395cef03SMartin K. Petersen 			(u32)cmd[21] << 16 | (u32)cmd[20] << 24;
353395cef03SMartin K. Petersen 
354395cef03SMartin K. Petersen 		*num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 |
355395cef03SMartin K. Petersen 			(u32)cmd[28] << 24;
356395cef03SMartin K. Petersen 		break;
357395cef03SMartin K. Petersen 
35844d92694SMartin K. Petersen 	case WRITE_SAME_16:
3593de9f944SFUJITA Tomonori 	case WRITE_16:
3603de9f944SFUJITA Tomonori 	case READ_16:
361d5cdc989SFUJITA Tomonori 		*lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
362d5cdc989SFUJITA Tomonori 			(u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
363d5cdc989SFUJITA Tomonori 			(u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
364d5cdc989SFUJITA Tomonori 			(u64)cmd[3] << 48 | (u64)cmd[2] << 56;
365d5cdc989SFUJITA Tomonori 
366d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
367d5cdc989SFUJITA Tomonori 			(u32)cmd[10] << 24;
3683de9f944SFUJITA Tomonori 		break;
3693de9f944SFUJITA Tomonori 	case WRITE_12:
3703de9f944SFUJITA Tomonori 	case READ_12:
371d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
372d5cdc989SFUJITA Tomonori 			(u32)cmd[2] << 24;
373d5cdc989SFUJITA Tomonori 
374d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
375d5cdc989SFUJITA Tomonori 			(u32)cmd[6] << 24;
3763de9f944SFUJITA Tomonori 		break;
37744d92694SMartin K. Petersen 	case WRITE_SAME:
3783de9f944SFUJITA Tomonori 	case WRITE_10:
3793de9f944SFUJITA Tomonori 	case READ_10:
380c639d14eSFUJITA Tomonori 	case XDWRITEREAD_10:
381d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[5] | (u32)cmd[4] << 8 |	(u32)cmd[3] << 16 |
382d5cdc989SFUJITA Tomonori 			(u32)cmd[2] << 24;
383d5cdc989SFUJITA Tomonori 
384d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[8] | (u32)cmd[7] << 8;
3853de9f944SFUJITA Tomonori 		break;
3863de9f944SFUJITA Tomonori 	case WRITE_6:
3873de9f944SFUJITA Tomonori 	case READ_6:
388d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
389d5cdc989SFUJITA Tomonori 			(u32)(cmd[1] & 0x1f) << 16;
3903de9f944SFUJITA Tomonori 		*num = (0 == cmd[4]) ? 256 : cmd[4];
3913de9f944SFUJITA Tomonori 		break;
3923de9f944SFUJITA Tomonori 	default:
3933de9f944SFUJITA Tomonori 		break;
3943de9f944SFUJITA Tomonori 	}
3953de9f944SFUJITA Tomonori }
3961da177e4SLinus Torvalds 
3971da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
3981da177e4SLinus Torvalds {
3991da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
4001da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
4011da177e4SLinus Torvalds 	}
4021da177e4SLinus Torvalds 	return -EINVAL;
4031da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
4041da177e4SLinus Torvalds }
4051da177e4SLinus Torvalds 
406c65b1445SDouglas Gilbert static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
407c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
4081da177e4SLinus Torvalds {
4091da177e4SLinus Torvalds 	if (devip->reset) {
4101da177e4SLinus Torvalds 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
4111da177e4SLinus Torvalds 			printk(KERN_INFO "scsi_debug: Reporting Unit "
4121da177e4SLinus Torvalds 			       "attention: power on reset\n");
4131da177e4SLinus Torvalds 		devip->reset = 0;
4141da177e4SLinus Torvalds 		mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
4151da177e4SLinus Torvalds 		return check_condition_result;
4161da177e4SLinus Torvalds 	}
417c65b1445SDouglas Gilbert 	if ((0 == reset_only) && devip->stopped) {
418c65b1445SDouglas Gilbert 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
419c65b1445SDouglas Gilbert 			printk(KERN_INFO "scsi_debug: Reporting Not "
420c65b1445SDouglas Gilbert 			       "ready: initializing command required\n");
421c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
422c65b1445SDouglas Gilbert 				0x2);
423c65b1445SDouglas Gilbert 		return check_condition_result;
424c65b1445SDouglas Gilbert 	}
4251da177e4SLinus Torvalds 	return 0;
4261da177e4SLinus Torvalds }
4271da177e4SLinus Torvalds 
4281da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
4291da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
4301da177e4SLinus Torvalds 				int arr_len)
4311da177e4SLinus Torvalds {
43221a61829SFUJITA Tomonori 	int act_len;
433072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
4341da177e4SLinus Torvalds 
435072d0bb3SFUJITA Tomonori 	if (!sdb->length)
4361da177e4SLinus Torvalds 		return 0;
437072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
4381da177e4SLinus Torvalds 		return (DID_ERROR << 16);
43921a61829SFUJITA Tomonori 
44021a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
44121a61829SFUJITA Tomonori 				      arr, arr_len);
44221a61829SFUJITA Tomonori 	sdb->resid = scsi_bufflen(scp) - act_len;
44321a61829SFUJITA Tomonori 
4441da177e4SLinus Torvalds 	return 0;
4451da177e4SLinus Torvalds }
4461da177e4SLinus Torvalds 
4471da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */
4481da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
44921a61829SFUJITA Tomonori 			       int arr_len)
4501da177e4SLinus Torvalds {
45121a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
4521da177e4SLinus Torvalds 		return 0;
453072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
4541da177e4SLinus Torvalds 		return -1;
45521a61829SFUJITA Tomonori 
45621a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
4571da177e4SLinus Torvalds }
4581da177e4SLinus Torvalds 
4591da177e4SLinus Torvalds 
4601da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux   ";
4611da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug      ";
4621da177e4SLinus Torvalds static const char * inq_product_rev = "0004";
4631da177e4SLinus Torvalds 
4645a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
4655a09e398SHannes Reinecke 			   int target_dev_id, int dev_id_num,
4665a09e398SHannes Reinecke 			   const char * dev_id_str,
467c65b1445SDouglas Gilbert 			   int dev_id_str_len)
4681da177e4SLinus Torvalds {
469c65b1445SDouglas Gilbert 	int num, port_a;
470c65b1445SDouglas Gilbert 	char b[32];
4711da177e4SLinus Torvalds 
472c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
4731da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
4741da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
4751da177e4SLinus Torvalds 	arr[1] = 0x1;
4761da177e4SLinus Torvalds 	arr[2] = 0x0;
4771da177e4SLinus Torvalds 	memcpy(&arr[4], inq_vendor_id, 8);
4781da177e4SLinus Torvalds 	memcpy(&arr[12], inq_product_id, 16);
4791da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
4801da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
4811da177e4SLinus Torvalds 	arr[3] = num;
4821da177e4SLinus Torvalds 	num += 4;
483c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
484c65b1445SDouglas Gilbert 		/* NAA-5, Logical unit identifier (binary) */
485c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* binary (not necessarily sas) */
486c65b1445SDouglas Gilbert 		arr[num++] = 0x3;	/* PIV=0, lu, naa */
487c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
488c65b1445SDouglas Gilbert 		arr[num++] = 0x8;
489c65b1445SDouglas Gilbert 		arr[num++] = 0x53;  /* naa-5 ieee company id=0x333333 (fake) */
490c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
491c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
492c65b1445SDouglas Gilbert 		arr[num++] = 0x30;
493c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 24);
494c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 16) & 0xff;
495c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 8) & 0xff;
496c65b1445SDouglas Gilbert 		arr[num++] = dev_id_num & 0xff;
497c65b1445SDouglas Gilbert 		/* Target relative port number */
498c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
499c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
500c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
501c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
502c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
503c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
504c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
505c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
506c65b1445SDouglas Gilbert 	}
507c65b1445SDouglas Gilbert 	/* NAA-5, Target port identifier */
508c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
509c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
510c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
511c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
512c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
513c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
514c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
515c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
516c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
517c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
518c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
519c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
5205a09e398SHannes Reinecke 	/* NAA-5, Target port group identifier */
5215a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
5225a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
5235a09e398SHannes Reinecke 	arr[num++] = 0x0;
5245a09e398SHannes Reinecke 	arr[num++] = 0x4;
5255a09e398SHannes Reinecke 	arr[num++] = 0;
5265a09e398SHannes Reinecke 	arr[num++] = 0;
5275a09e398SHannes Reinecke 	arr[num++] = (port_group_id >> 8) & 0xff;
5285a09e398SHannes Reinecke 	arr[num++] = port_group_id & 0xff;
529c65b1445SDouglas Gilbert 	/* NAA-5, Target device identifier */
530c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
531c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
532c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
533c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
534c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
535c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
536c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
537c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
538c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 24);
539c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 16) & 0xff;
540c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 8) & 0xff;
541c65b1445SDouglas Gilbert 	arr[num++] = target_dev_id & 0xff;
542c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
543c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
544c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
545c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
546c65b1445SDouglas Gilbert 	arr[num++] = 24;
547c65b1445SDouglas Gilbert 	memcpy(arr + num, "naa.52222220", 12);
548c65b1445SDouglas Gilbert 	num += 12;
549c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
550c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
551c65b1445SDouglas Gilbert 	num += 8;
552c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
553c65b1445SDouglas Gilbert 	num += 4;
554c65b1445SDouglas Gilbert 	return num;
555c65b1445SDouglas Gilbert }
556c65b1445SDouglas Gilbert 
557c65b1445SDouglas Gilbert 
558c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
559c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
560c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
561c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
562c65b1445SDouglas Gilbert };
563c65b1445SDouglas Gilbert 
564c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr)
565c65b1445SDouglas Gilbert {
566c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
567c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
568c65b1445SDouglas Gilbert }
569c65b1445SDouglas Gilbert 
570c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr)
571c65b1445SDouglas Gilbert {
572c65b1445SDouglas Gilbert 	int num = 0;
573c65b1445SDouglas Gilbert 	const char * na1 = "https://www.kernel.org/config";
574c65b1445SDouglas Gilbert 	const char * na2 = "http://www.kernel.org/log";
575c65b1445SDouglas Gilbert 	int plen, olen;
576c65b1445SDouglas Gilbert 
577c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
578c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
579c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
580c65b1445SDouglas Gilbert 	olen = strlen(na1);
581c65b1445SDouglas Gilbert 	plen = olen + 1;
582c65b1445SDouglas Gilbert 	if (plen % 4)
583c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
584c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
585c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
586c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
587c65b1445SDouglas Gilbert 	num += plen;
588c65b1445SDouglas Gilbert 
589c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
590c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
591c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
592c65b1445SDouglas Gilbert 	olen = strlen(na2);
593c65b1445SDouglas Gilbert 	plen = olen + 1;
594c65b1445SDouglas Gilbert 	if (plen % 4)
595c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
596c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
597c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
598c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
599c65b1445SDouglas Gilbert 	num += plen;
600c65b1445SDouglas Gilbert 
601c65b1445SDouglas Gilbert 	return num;
602c65b1445SDouglas Gilbert }
603c65b1445SDouglas Gilbert 
604c65b1445SDouglas Gilbert /* SCSI ports VPD page */
605c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
606c65b1445SDouglas Gilbert {
607c65b1445SDouglas Gilbert 	int num = 0;
608c65b1445SDouglas Gilbert 	int port_a, port_b;
609c65b1445SDouglas Gilbert 
610c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
611c65b1445SDouglas Gilbert 	port_b = port_a + 1;
612c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
613c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
614c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
615c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
616c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
617c65b1445SDouglas Gilbert 	num += 6;
618c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
619c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
620c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
621c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
622c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
623c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
624c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
625c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
626c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
627c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
628c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
629c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
630c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
631c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
632c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
633c65b1445SDouglas Gilbert 
634c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
635c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
636c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
637c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
638c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
639c65b1445SDouglas Gilbert 	num += 6;
640c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
641c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
642c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
643c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
644c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
645c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
646c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
647c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
648c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
649c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
650c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
651c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 24);
652c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 16) & 0xff;
653c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 8) & 0xff;
654c65b1445SDouglas Gilbert 	arr[num++] = port_b & 0xff;
655c65b1445SDouglas Gilbert 
656c65b1445SDouglas Gilbert 	return num;
657c65b1445SDouglas Gilbert }
658c65b1445SDouglas Gilbert 
659c65b1445SDouglas Gilbert 
660c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
661c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
662c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
663c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
664c65b1445SDouglas Gilbert '1','2','3','4',
665c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
666c65b1445SDouglas Gilbert 0xec,0,0,0,
667c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
668c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
669c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
670c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
671c65b1445SDouglas Gilbert 0x53,0x41,
672c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
673c65b1445SDouglas Gilbert 0x20,0x20,
674c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
675c65b1445SDouglas Gilbert 0x10,0x80,
676c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
677c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
678c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
679c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
680c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
681c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
682c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
683c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
684c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
685c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
686c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
687c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
688c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
689c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
690c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
691c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
692c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
693c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
694c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
695c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
696c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
697c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
698c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
699c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
700c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
701c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
702c65b1445SDouglas Gilbert };
703c65b1445SDouglas Gilbert 
704c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr)
705c65b1445SDouglas Gilbert {
706c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
707c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
708c65b1445SDouglas Gilbert }
709c65b1445SDouglas Gilbert 
710c65b1445SDouglas Gilbert 
7111e49f785SDouglas Gilbert /* Block limits VPD page (SBC-3) */
712c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
7131e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
7141e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7151e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7161e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
717c65b1445SDouglas Gilbert };
718c65b1445SDouglas Gilbert 
719c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr)
720c65b1445SDouglas Gilbert {
721ea61fca5SMartin K. Petersen 	unsigned int gran;
722ea61fca5SMartin K. Petersen 
723c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
724e308b3d1SMartin K. Petersen 
725e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
726ea61fca5SMartin K. Petersen 	gran = 1 << scsi_debug_physblk_exp;
727ea61fca5SMartin K. Petersen 	arr[2] = (gran >> 8) & 0xff;
728ea61fca5SMartin K. Petersen 	arr[3] = gran & 0xff;
729e308b3d1SMartin K. Petersen 
730e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
731c65b1445SDouglas Gilbert 	if (sdebug_store_sectors > 0x400) {
732c65b1445SDouglas Gilbert 		arr[4] = (sdebug_store_sectors >> 24) & 0xff;
733c65b1445SDouglas Gilbert 		arr[5] = (sdebug_store_sectors >> 16) & 0xff;
734c65b1445SDouglas Gilbert 		arr[6] = (sdebug_store_sectors >> 8) & 0xff;
735c65b1445SDouglas Gilbert 		arr[7] = sdebug_store_sectors & 0xff;
736c65b1445SDouglas Gilbert 	}
73744d92694SMartin K. Petersen 
738e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
739e308b3d1SMartin K. Petersen 	put_unaligned_be32(scsi_debug_opt_blks, &arr[8]);
740e308b3d1SMartin K. Petersen 
7415b94e232SMartin K. Petersen 	if (scsi_debug_lbpu) {
742e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
7436014759cSMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]);
744e308b3d1SMartin K. Petersen 
745e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
74644d92694SMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
74744d92694SMartin K. Petersen 	}
74844d92694SMartin K. Petersen 
749e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
75044d92694SMartin K. Petersen 	if (scsi_debug_unmap_alignment) {
75144d92694SMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
75244d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
75344d92694SMartin K. Petersen 	}
75444d92694SMartin K. Petersen 
755e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
75644d92694SMartin K. Petersen 	put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
7576014759cSMartin K. Petersen 
7585b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
7595b94e232SMartin K. Petersen 	put_unaligned_be64(scsi_debug_write_same_length, &arr[32]);
7605b94e232SMartin K. Petersen 
7615b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
76244d92694SMartin K. Petersen 
763c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
7641da177e4SLinus Torvalds }
7651da177e4SLinus Torvalds 
7661e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
767eac6e8e4SMatthew Wilcox static int inquiry_evpd_b1(unsigned char *arr)
768eac6e8e4SMatthew Wilcox {
769eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
770eac6e8e4SMatthew Wilcox 	arr[0] = 0;
7711e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
7721e49f785SDouglas Gilbert 	arr[2] = 0;
7731e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
774eac6e8e4SMatthew Wilcox 
775eac6e8e4SMatthew Wilcox 	return 0x3c;
776eac6e8e4SMatthew Wilcox }
7771da177e4SLinus Torvalds 
778be1dd78dSEric Sandeen /* Logical block provisioning VPD page (SBC-3) */
7796014759cSMartin K. Petersen static int inquiry_evpd_b2(unsigned char *arr)
7806014759cSMartin K. Petersen {
7813f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
7826014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
7836014759cSMartin K. Petersen 
7845b94e232SMartin K. Petersen 	if (scsi_debug_lbpu)
7856014759cSMartin K. Petersen 		arr[1] = 1 << 7;
7866014759cSMartin K. Petersen 
7875b94e232SMartin K. Petersen 	if (scsi_debug_lbpws)
7886014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
7896014759cSMartin K. Petersen 
7905b94e232SMartin K. Petersen 	if (scsi_debug_lbpws10)
7915b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
7925b94e232SMartin K. Petersen 
793be1dd78dSEric Sandeen 	if (scsi_debug_lbprz)
794be1dd78dSEric Sandeen 		arr[1] |= 1 << 2;
795be1dd78dSEric Sandeen 
7963f0bc3b3SMartin K. Petersen 	return 0x4;
7976014759cSMartin K. Petersen }
7986014759cSMartin K. Petersen 
7991da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
800c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
8011da177e4SLinus Torvalds 
8021da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd * scp, int target,
8031da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
8041da177e4SLinus Torvalds {
8051da177e4SLinus Torvalds 	unsigned char pq_pdt;
8065a09e398SHannes Reinecke 	unsigned char * arr;
8071da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
8085a09e398SHannes Reinecke 	int alloc_len, n, ret;
8091da177e4SLinus Torvalds 
8101da177e4SLinus Torvalds 	alloc_len = (cmd[3] << 8) + cmd[4];
8116f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
8126f3cbf55SDouglas Gilbert 	if (! arr)
8136f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
814c65b1445SDouglas Gilbert 	if (devip->wlun)
815c65b1445SDouglas Gilbert 		pq_pdt = 0x1e;	/* present, wlun */
816c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (0 == devip->lun))
817c65b1445SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, no device type */
818c65b1445SDouglas Gilbert 	else
8191da177e4SLinus Torvalds 		pq_pdt = (scsi_debug_ptype & 0x1f);
8201da177e4SLinus Torvalds 	arr[0] = pq_pdt;
8211da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
8221da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
8231da177e4SLinus Torvalds 			       	0);
8245a09e398SHannes Reinecke 		kfree(arr);
8251da177e4SLinus Torvalds 		return check_condition_result;
8261da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
8275a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
828c65b1445SDouglas Gilbert 		char lu_id_str[6];
829c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
8301da177e4SLinus Torvalds 
8315a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
8325a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
83323183910SDouglas Gilbert 		if (0 == scsi_debug_vpd_use_hostno)
83423183910SDouglas Gilbert 			host_no = 0;
835c65b1445SDouglas Gilbert 		lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
836c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
837c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
838c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
839c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
8401da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
841c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
842c65b1445SDouglas Gilbert 			n = 4;
843c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
844c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
845c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
846c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
847c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
848c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
849c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
850c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
851c65b1445SDouglas Gilbert 			arr[n++] = 0x89;  /* ATA information */
852c65b1445SDouglas Gilbert 			arr[n++] = 0xb0;  /* Block limits (SBC) */
853eac6e8e4SMatthew Wilcox 			arr[n++] = 0xb1;  /* Block characteristics (SBC) */
8545b94e232SMartin K. Petersen 			if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
8555b94e232SMartin K. Petersen 				arr[n++] = 0xb2;
856c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
8571da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
858c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
8591da177e4SLinus Torvalds 			arr[3] = len;
860c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
8611da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
862c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
8635a09e398SHannes Reinecke 			arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
8645a09e398SHannes Reinecke 						 target_dev_id, lu_id_num,
8655a09e398SHannes Reinecke 						 lu_id_str, len);
866c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
867c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
868c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_84(&arr[4]);
869c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
870c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
871c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_85(&arr[4]);
872c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
873c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
874c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
875c6a44287SMartin K. Petersen 			if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
876c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
877c6a44287SMartin K. Petersen 			else if (scsi_debug_dif)
878c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
879c6a44287SMartin K. Petersen 			else
880c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
881c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
882c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
883c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
884c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
885c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
886c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
887c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
888c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
889c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
890c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
891c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
892c65b1445SDouglas Gilbert 		} else if (0x89 == cmd[2]) { /* ATA information */
893c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
894c65b1445SDouglas Gilbert 			n = inquiry_evpd_89(&arr[4]);
895c65b1445SDouglas Gilbert 			arr[2] = (n >> 8);
896c65b1445SDouglas Gilbert 			arr[3] = (n & 0xff);
897c65b1445SDouglas Gilbert 		} else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
898c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
899c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_b0(&arr[4]);
900eac6e8e4SMatthew Wilcox 		} else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
901eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
902eac6e8e4SMatthew Wilcox 			arr[3] = inquiry_evpd_b1(&arr[4]);
9035b94e232SMartin K. Petersen 		} else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
9046014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
9056014759cSMartin K. Petersen 			arr[3] = inquiry_evpd_b2(&arr[4]);
9061da177e4SLinus Torvalds 		} else {
9071da177e4SLinus Torvalds 			/* Illegal request, invalid field in cdb */
9081da177e4SLinus Torvalds 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
9091da177e4SLinus Torvalds 					INVALID_FIELD_IN_CDB, 0);
9105a09e398SHannes Reinecke 			kfree(arr);
9111da177e4SLinus Torvalds 			return check_condition_result;
9121da177e4SLinus Torvalds 		}
913c65b1445SDouglas Gilbert 		len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
9145a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
915c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
9165a09e398SHannes Reinecke 		kfree(arr);
9175a09e398SHannes Reinecke 		return ret;
9181da177e4SLinus Torvalds 	}
9191da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
920d986788bSMartin Pitt 	arr[1] = scsi_debug_removable ? 0x80 : 0;	/* Removable disk */
9211da177e4SLinus Torvalds 	arr[2] = scsi_debug_scsi_level;
9221da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
9231da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
924c6a44287SMartin K. Petersen 	arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
9255a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno)
9265a09e398SHannes Reinecke 		arr[5] = 0x10; /* claim: implicit TGPS */
927c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
9281da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
929c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
9301da177e4SLinus Torvalds 	memcpy(&arr[8], inq_vendor_id, 8);
9311da177e4SLinus Torvalds 	memcpy(&arr[16], inq_product_id, 16);
9321da177e4SLinus Torvalds 	memcpy(&arr[32], inq_product_rev, 4);
9331da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
934c65b1445SDouglas Gilbert 	arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
935c65b1445SDouglas Gilbert 	arr[60] = 0x3; arr[61] = 0x14;  /* SPC-3 ANSI */
936c65b1445SDouglas Gilbert 	n = 62;
9371da177e4SLinus Torvalds 	if (scsi_debug_ptype == 0) {
938c65b1445SDouglas Gilbert 		arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
9391da177e4SLinus Torvalds 	} else if (scsi_debug_ptype == 1) {
940c65b1445SDouglas Gilbert 		arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
9411da177e4SLinus Torvalds 	}
942c65b1445SDouglas Gilbert 	arr[n++] = 0xc; arr[n++] = 0xf;  /* SAS-1.1 rev 10 */
9435a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
9441da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
9455a09e398SHannes Reinecke 	kfree(arr);
9465a09e398SHannes Reinecke 	return ret;
9471da177e4SLinus Torvalds }
9481da177e4SLinus Torvalds 
9491da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp,
9501da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip)
9511da177e4SLinus Torvalds {
9521da177e4SLinus Torvalds 	unsigned char * sbuff;
9531da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
9541da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_SENSE_LEN];
955c65b1445SDouglas Gilbert 	int want_dsense;
9561da177e4SLinus Torvalds 	int len = 18;
9571da177e4SLinus Torvalds 
958c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
9591da177e4SLinus Torvalds 	if (devip->reset == 1)
960c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
961c65b1445SDouglas Gilbert 	want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
9621da177e4SLinus Torvalds 	sbuff = devip->sense_buff;
963c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
964c65b1445SDouglas Gilbert 		if (want_dsense) {
965c65b1445SDouglas Gilbert 			arr[0] = 0x72;
966c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
967c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
968c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
969c65b1445SDouglas Gilbert 		} else {
970c65b1445SDouglas Gilbert 			arr[0] = 0x70;
971c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
972c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
973c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
974c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
975c65b1445SDouglas Gilbert 		}
976c65b1445SDouglas Gilbert 	} else {
977c65b1445SDouglas Gilbert 		memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
9781da177e4SLinus Torvalds 		if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
9791da177e4SLinus Torvalds 			/* DESC bit set and sense_buff in fixed format */
980c65b1445SDouglas Gilbert 			memset(arr, 0, sizeof(arr));
9811da177e4SLinus Torvalds 			arr[0] = 0x72;
9821da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
9831da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
9841da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
9851da177e4SLinus Torvalds 			len = 8;
986c65b1445SDouglas Gilbert 		}
987c65b1445SDouglas Gilbert 	}
988c65b1445SDouglas Gilbert 	mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
9891da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
9901da177e4SLinus Torvalds }
9911da177e4SLinus Torvalds 
992c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp,
993c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
994c65b1445SDouglas Gilbert {
995c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
996c65b1445SDouglas Gilbert 	int power_cond, errsts, start;
997c65b1445SDouglas Gilbert 
998c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
999c65b1445SDouglas Gilbert 		return errsts;
1000c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1001c65b1445SDouglas Gilbert 	if (power_cond) {
1002c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1003c65b1445SDouglas Gilbert 			       	0);
1004c65b1445SDouglas Gilbert 		return check_condition_result;
1005c65b1445SDouglas Gilbert 	}
1006c65b1445SDouglas Gilbert 	start = cmd[4] & 1;
1007c65b1445SDouglas Gilbert 	if (start == devip->stopped)
1008c65b1445SDouglas Gilbert 		devip->stopped = !start;
1009c65b1445SDouglas Gilbert 	return 0;
1010c65b1445SDouglas Gilbert }
1011c65b1445SDouglas Gilbert 
101228898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
101328898873SFUJITA Tomonori {
101428898873SFUJITA Tomonori 	if (scsi_debug_virtual_gb > 0)
10155447ed6cSDouglas Gilbert 		return (sector_t)scsi_debug_virtual_gb *
10165447ed6cSDouglas Gilbert 			(1073741824 / scsi_debug_sector_size);
101728898873SFUJITA Tomonori 	else
101828898873SFUJITA Tomonori 		return sdebug_store_sectors;
101928898873SFUJITA Tomonori }
102028898873SFUJITA Tomonori 
10211da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
10221da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp,
10231da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
10241da177e4SLinus Torvalds {
10251da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1026c65b1445SDouglas Gilbert 	unsigned int capac;
10271da177e4SLinus Torvalds 	int errsts;
10281da177e4SLinus Torvalds 
1029c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
10301da177e4SLinus Torvalds 		return errsts;
1031c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
103228898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
10331da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1034c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1035c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
10361da177e4SLinus Torvalds 		arr[0] = (capac >> 24);
10371da177e4SLinus Torvalds 		arr[1] = (capac >> 16) & 0xff;
10381da177e4SLinus Torvalds 		arr[2] = (capac >> 8) & 0xff;
10391da177e4SLinus Torvalds 		arr[3] = capac & 0xff;
1040c65b1445SDouglas Gilbert 	} else {
1041c65b1445SDouglas Gilbert 		arr[0] = 0xff;
1042c65b1445SDouglas Gilbert 		arr[1] = 0xff;
1043c65b1445SDouglas Gilbert 		arr[2] = 0xff;
1044c65b1445SDouglas Gilbert 		arr[3] = 0xff;
1045c65b1445SDouglas Gilbert 	}
1046597136abSMartin K. Petersen 	arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
1047597136abSMartin K. Petersen 	arr[7] = scsi_debug_sector_size & 0xff;
10481da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
10491da177e4SLinus Torvalds }
10501da177e4SLinus Torvalds 
1051c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1052c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp,
1053c65b1445SDouglas Gilbert 			  struct sdebug_dev_info * devip)
1054c65b1445SDouglas Gilbert {
1055c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1056c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1057c65b1445SDouglas Gilbert 	unsigned long long capac;
1058c65b1445SDouglas Gilbert 	int errsts, k, alloc_len;
1059c65b1445SDouglas Gilbert 
1060c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1061c65b1445SDouglas Gilbert 		return errsts;
1062c65b1445SDouglas Gilbert 	alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1063c65b1445SDouglas Gilbert 		     + cmd[13]);
1064c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
106528898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1066c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1067c65b1445SDouglas Gilbert 	capac = sdebug_capacity - 1;
1068c65b1445SDouglas Gilbert 	for (k = 0; k < 8; ++k, capac >>= 8)
1069c65b1445SDouglas Gilbert 		arr[7 - k] = capac & 0xff;
1070597136abSMartin K. Petersen 	arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
1071597136abSMartin K. Petersen 	arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
1072597136abSMartin K. Petersen 	arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
1073597136abSMartin K. Petersen 	arr[11] = scsi_debug_sector_size & 0xff;
1074ea61fca5SMartin K. Petersen 	arr[13] = scsi_debug_physblk_exp & 0xf;
1075ea61fca5SMartin K. Petersen 	arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
107644d92694SMartin K. Petersen 
1077be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
10785b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1079be1dd78dSEric Sandeen 		if (scsi_debug_lbprz)
1080be1dd78dSEric Sandeen 			arr[14] |= 0x40; /* LBPRZ */
1081be1dd78dSEric Sandeen 	}
108244d92694SMartin K. Petersen 
1083ea61fca5SMartin K. Petersen 	arr[15] = scsi_debug_lowest_aligned & 0xff;
1084c6a44287SMartin K. Petersen 
1085c6a44287SMartin K. Petersen 	if (scsi_debug_dif) {
1086c6a44287SMartin K. Petersen 		arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
1087c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1088c6a44287SMartin K. Petersen 	}
1089c6a44287SMartin K. Petersen 
1090c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1091c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1092c65b1445SDouglas Gilbert }
1093c65b1445SDouglas Gilbert 
10945a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
10955a09e398SHannes Reinecke 
10965a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp,
10975a09e398SHannes Reinecke 			      struct sdebug_dev_info * devip)
10985a09e398SHannes Reinecke {
10995a09e398SHannes Reinecke 	unsigned char *cmd = (unsigned char *)scp->cmnd;
11005a09e398SHannes Reinecke 	unsigned char * arr;
11015a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
11025a09e398SHannes Reinecke 	int n, ret, alen, rlen;
11035a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
11045a09e398SHannes Reinecke 
11055a09e398SHannes Reinecke 	alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
11065a09e398SHannes Reinecke 		+ cmd[9]);
11075a09e398SHannes Reinecke 
11086f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
11096f3cbf55SDouglas Gilbert 	if (! arr)
11106f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
11115a09e398SHannes Reinecke 	/*
11125a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
11135a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
11145a09e398SHannes Reinecke 	 * So we create two port groups with one port each
11155a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
11165a09e398SHannes Reinecke 	 */
11175a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
11185a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
11195a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
11205a09e398SHannes Reinecke 	    (devip->channel & 0x7f);
11215a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
11225a09e398SHannes Reinecke 	    (devip->channel & 0x7f) + 0x80;
11235a09e398SHannes Reinecke 
11245a09e398SHannes Reinecke 	/*
11255a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
11265a09e398SHannes Reinecke 	 */
11275a09e398SHannes Reinecke 	n = 4;
11285a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno) {
11295a09e398SHannes Reinecke 	    arr[n++] = host_no % 3; /* Asymm access state */
11305a09e398SHannes Reinecke 	    arr[n++] = 0x0F; /* claim: all states are supported */
11315a09e398SHannes Reinecke 	} else {
11325a09e398SHannes Reinecke 	    arr[n++] = 0x0; /* Active/Optimized path */
11335a09e398SHannes Reinecke 	    arr[n++] = 0x01; /* claim: only support active/optimized paths */
11345a09e398SHannes Reinecke 	}
11355a09e398SHannes Reinecke 	arr[n++] = (port_group_a >> 8) & 0xff;
11365a09e398SHannes Reinecke 	arr[n++] = port_group_a & 0xff;
11375a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11385a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
11395a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
11405a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
11415a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11425a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11435a09e398SHannes Reinecke 	arr[n++] = (port_a >> 8) & 0xff;
11445a09e398SHannes Reinecke 	arr[n++] = port_a & 0xff;
11455a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
11465a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
11475a09e398SHannes Reinecke 	arr[n++] = (port_group_b >> 8) & 0xff;
11485a09e398SHannes Reinecke 	arr[n++] = port_group_b & 0xff;
11495a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11505a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
11515a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
11525a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
11535a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11545a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11555a09e398SHannes Reinecke 	arr[n++] = (port_b >> 8) & 0xff;
11565a09e398SHannes Reinecke 	arr[n++] = port_b & 0xff;
11575a09e398SHannes Reinecke 
11585a09e398SHannes Reinecke 	rlen = n - 4;
11595a09e398SHannes Reinecke 	arr[0] = (rlen >> 24) & 0xff;
11605a09e398SHannes Reinecke 	arr[1] = (rlen >> 16) & 0xff;
11615a09e398SHannes Reinecke 	arr[2] = (rlen >> 8) & 0xff;
11625a09e398SHannes Reinecke 	arr[3] = rlen & 0xff;
11635a09e398SHannes Reinecke 
11645a09e398SHannes Reinecke 	/*
11655a09e398SHannes Reinecke 	 * Return the smallest value of either
11665a09e398SHannes Reinecke 	 * - The allocated length
11675a09e398SHannes Reinecke 	 * - The constructed command length
11685a09e398SHannes Reinecke 	 * - The maximum array size
11695a09e398SHannes Reinecke 	 */
11705a09e398SHannes Reinecke 	rlen = min(alen,n);
11715a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
11725a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
11735a09e398SHannes Reinecke 	kfree(arr);
11745a09e398SHannes Reinecke 	return ret;
11755a09e398SHannes Reinecke }
11765a09e398SHannes Reinecke 
11771da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
11781da177e4SLinus Torvalds 
11791da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
11801da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
11811da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
11821da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
11831da177e4SLinus Torvalds 
11841da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
11851da177e4SLinus Torvalds 	if (1 == pcontrol)
11861da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
11871da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
11881da177e4SLinus Torvalds }
11891da177e4SLinus Torvalds 
11901da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
11911da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
11921da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
11931da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
11941da177e4SLinus Torvalds 
11951da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
11961da177e4SLinus Torvalds 	if (1 == pcontrol)
11971da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
11981da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
11991da177e4SLinus Torvalds }
12001da177e4SLinus Torvalds 
12011da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target)
12021da177e4SLinus Torvalds {       /* Format device page for mode_sense */
12031da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
12041da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
12051da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
12061da177e4SLinus Torvalds 
12071da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
12081da177e4SLinus Torvalds 	p[10] = (sdebug_sectors_per >> 8) & 0xff;
12091da177e4SLinus Torvalds 	p[11] = sdebug_sectors_per & 0xff;
1210597136abSMartin K. Petersen 	p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1211597136abSMartin K. Petersen 	p[13] = scsi_debug_sector_size & 0xff;
1212d986788bSMartin Pitt 	if (scsi_debug_removable)
12131da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
12141da177e4SLinus Torvalds 	if (1 == pcontrol)
12151da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
12161da177e4SLinus Torvalds 	return sizeof(format_pg);
12171da177e4SLinus Torvalds }
12181da177e4SLinus Torvalds 
12191da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
12201da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
12211da177e4SLinus Torvalds 	unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
12221da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
12231da177e4SLinus Torvalds 
12241da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
12251da177e4SLinus Torvalds 	if (1 == pcontrol)
12261da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(caching_pg) - 2);
12271da177e4SLinus Torvalds 	return sizeof(caching_pg);
12281da177e4SLinus Torvalds }
12291da177e4SLinus Torvalds 
12301da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
12311da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
1232c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1233c65b1445SDouglas Gilbert 				        0, 0, 0, 0};
1234c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
12351da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
12361da177e4SLinus Torvalds 
12371da177e4SLinus Torvalds 	if (scsi_debug_dsense)
12381da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
1239c65b1445SDouglas Gilbert 	else
1240c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
1241c6a44287SMartin K. Petersen 
1242c6a44287SMartin K. Petersen 	if (scsi_debug_ato)
1243c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1244c6a44287SMartin K. Petersen 
12451da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
12461da177e4SLinus Torvalds 	if (1 == pcontrol)
1247c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1248c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1249c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
12501da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
12511da177e4SLinus Torvalds }
12521da177e4SLinus Torvalds 
1253c65b1445SDouglas Gilbert 
12541da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
12551da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
1256c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
12571da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
1258c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1259c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
1260c65b1445SDouglas Gilbert 
12611da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
12621da177e4SLinus Torvalds 	if (1 == pcontrol)
1263c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1264c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1265c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
12661da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
12671da177e4SLinus Torvalds }
12681da177e4SLinus Torvalds 
1269c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1270c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
1271c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1272c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1273c65b1445SDouglas Gilbert 
1274c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1275c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1276c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1277c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
1278c65b1445SDouglas Gilbert }
1279c65b1445SDouglas Gilbert 
1280c65b1445SDouglas Gilbert 
1281c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1282c65b1445SDouglas Gilbert 			      int target_dev_id)
1283c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
1284c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1285c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1286c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1287c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1288c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
1289c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1290c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1291c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1292c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1293c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1294c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
1295c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1296c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1297c65b1445SDouglas Gilbert 		};
1298c65b1445SDouglas Gilbert 	int port_a, port_b;
1299c65b1445SDouglas Gilbert 
1300c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1301c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1302c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1303c65b1445SDouglas Gilbert 	p[20] = (port_a >> 24);
1304c65b1445SDouglas Gilbert 	p[21] = (port_a >> 16) & 0xff;
1305c65b1445SDouglas Gilbert 	p[22] = (port_a >> 8) & 0xff;
1306c65b1445SDouglas Gilbert 	p[23] = port_a & 0xff;
1307c65b1445SDouglas Gilbert 	p[48 + 20] = (port_b >> 24);
1308c65b1445SDouglas Gilbert 	p[48 + 21] = (port_b >> 16) & 0xff;
1309c65b1445SDouglas Gilbert 	p[48 + 22] = (port_b >> 8) & 0xff;
1310c65b1445SDouglas Gilbert 	p[48 + 23] = port_b & 0xff;
1311c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1312c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1313c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
1314c65b1445SDouglas Gilbert }
1315c65b1445SDouglas Gilbert 
1316c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1317c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
1318c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1319c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1320c65b1445SDouglas Gilbert 		};
1321c65b1445SDouglas Gilbert 
1322c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1323c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1324c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1325c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
1326c65b1445SDouglas Gilbert }
1327c65b1445SDouglas Gilbert 
13281da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
13291da177e4SLinus Torvalds 
13301da177e4SLinus Torvalds static int resp_mode_sense(struct scsi_cmnd * scp, int target,
13311da177e4SLinus Torvalds 			   struct sdebug_dev_info * devip)
13321da177e4SLinus Torvalds {
133323183910SDouglas Gilbert 	unsigned char dbd, llbaa;
133423183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
13351da177e4SLinus Torvalds 	unsigned char dev_spec;
133623183910SDouglas Gilbert 	int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
13371da177e4SLinus Torvalds 	unsigned char * ap;
13381da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
13391da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
13401da177e4SLinus Torvalds 
1341c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
13421da177e4SLinus Torvalds 		return errsts;
134323183910SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);
13441da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
13451da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
13461da177e4SLinus Torvalds 	subpcode = cmd[3];
13471da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
134823183910SDouglas Gilbert 	llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
134923183910SDouglas Gilbert 	if ((0 == scsi_debug_ptype) && (0 == dbd))
135023183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
135123183910SDouglas Gilbert 	else
135223183910SDouglas Gilbert 		bd_len = 0;
13531da177e4SLinus Torvalds 	alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
13541da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
13551da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
13561da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
13571da177e4SLinus Torvalds 			       	0);
13581da177e4SLinus Torvalds 		return check_condition_result;
13591da177e4SLinus Torvalds 	}
1360c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1361c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
136223183910SDouglas Gilbert 	/* set DPOFUA bit for disks */
136323183910SDouglas Gilbert 	if (0 == scsi_debug_ptype)
136423183910SDouglas Gilbert 		dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
136523183910SDouglas Gilbert 	else
136623183910SDouglas Gilbert 		dev_spec = 0x0;
13671da177e4SLinus Torvalds 	if (msense_6) {
13681da177e4SLinus Torvalds 		arr[2] = dev_spec;
136923183910SDouglas Gilbert 		arr[3] = bd_len;
13701da177e4SLinus Torvalds 		offset = 4;
13711da177e4SLinus Torvalds 	} else {
13721da177e4SLinus Torvalds 		arr[3] = dev_spec;
137323183910SDouglas Gilbert 		if (16 == bd_len)
137423183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
137523183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
13761da177e4SLinus Torvalds 		offset = 8;
13771da177e4SLinus Torvalds 	}
13781da177e4SLinus Torvalds 	ap = arr + offset;
137928898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
138028898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
138128898873SFUJITA Tomonori 
138223183910SDouglas Gilbert 	if (8 == bd_len) {
138323183910SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe) {
138423183910SDouglas Gilbert 			ap[0] = 0xff;
138523183910SDouglas Gilbert 			ap[1] = 0xff;
138623183910SDouglas Gilbert 			ap[2] = 0xff;
138723183910SDouglas Gilbert 			ap[3] = 0xff;
138823183910SDouglas Gilbert 		} else {
138923183910SDouglas Gilbert 			ap[0] = (sdebug_capacity >> 24) & 0xff;
139023183910SDouglas Gilbert 			ap[1] = (sdebug_capacity >> 16) & 0xff;
139123183910SDouglas Gilbert 			ap[2] = (sdebug_capacity >> 8) & 0xff;
139223183910SDouglas Gilbert 			ap[3] = sdebug_capacity & 0xff;
139323183910SDouglas Gilbert 		}
1394597136abSMartin K. Petersen 		ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1395597136abSMartin K. Petersen 		ap[7] = scsi_debug_sector_size & 0xff;
139623183910SDouglas Gilbert 		offset += bd_len;
139723183910SDouglas Gilbert 		ap = arr + offset;
139823183910SDouglas Gilbert 	} else if (16 == bd_len) {
139923183910SDouglas Gilbert 		unsigned long long capac = sdebug_capacity;
140023183910SDouglas Gilbert 
140123183910SDouglas Gilbert         	for (k = 0; k < 8; ++k, capac >>= 8)
140223183910SDouglas Gilbert                 	ap[7 - k] = capac & 0xff;
1403597136abSMartin K. Petersen 		ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1404597136abSMartin K. Petersen 		ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1405597136abSMartin K. Petersen 		ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1406597136abSMartin K. Petersen 		ap[15] = scsi_debug_sector_size & 0xff;
140723183910SDouglas Gilbert 		offset += bd_len;
140823183910SDouglas Gilbert 		ap = arr + offset;
140923183910SDouglas Gilbert 	}
14101da177e4SLinus Torvalds 
1411c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1412c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
14131da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
14141da177e4SLinus Torvalds 			       	0);
14151da177e4SLinus Torvalds 		return check_condition_result;
14161da177e4SLinus Torvalds 	}
14171da177e4SLinus Torvalds 	switch (pcode) {
14181da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
14191da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
14201da177e4SLinus Torvalds 		offset += len;
14211da177e4SLinus Torvalds 		break;
14221da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
14231da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
14241da177e4SLinus Torvalds 		offset += len;
14251da177e4SLinus Torvalds 		break;
14261da177e4SLinus Torvalds         case 0x3:       /* Format device page, direct access */
14271da177e4SLinus Torvalds                 len = resp_format_pg(ap, pcontrol, target);
14281da177e4SLinus Torvalds                 offset += len;
14291da177e4SLinus Torvalds                 break;
14301da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
14311da177e4SLinus Torvalds 		len = resp_caching_pg(ap, pcontrol, target);
14321da177e4SLinus Torvalds 		offset += len;
14331da177e4SLinus Torvalds 		break;
14341da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
14351da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
14361da177e4SLinus Torvalds 		offset += len;
14371da177e4SLinus Torvalds 		break;
1438c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
1439c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
1440c65b1445SDouglas Gilbert 		        mk_sense_buffer(devip, ILLEGAL_REQUEST,
1441c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1442c65b1445SDouglas Gilbert 			return check_condition_result;
1443c65b1445SDouglas Gilbert 	        }
1444c65b1445SDouglas Gilbert 		len = 0;
1445c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
1446c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1447c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
1448c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1449c65b1445SDouglas Gilbert 						  target_dev_id);
1450c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
1451c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
1452c65b1445SDouglas Gilbert 		offset += len;
1453c65b1445SDouglas Gilbert 		break;
14541da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
14551da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
14561da177e4SLinus Torvalds 		offset += len;
14571da177e4SLinus Torvalds 		break;
14581da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
1459c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
14601da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
14611da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
14621da177e4SLinus Torvalds 			len += resp_format_pg(ap + len, pcontrol, target);
14631da177e4SLinus Torvalds 			len += resp_caching_pg(ap + len, pcontrol, target);
14641da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1465c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1466c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
1467c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1468c65b1445SDouglas Gilbert 						  target, target_dev_id);
1469c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
1470c65b1445SDouglas Gilbert 			}
14711da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
1472c65b1445SDouglas Gilbert 		} else {
1473c65b1445SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
1474c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1475c65b1445SDouglas Gilbert 			return check_condition_result;
1476c65b1445SDouglas Gilbert                 }
14771da177e4SLinus Torvalds 		offset += len;
14781da177e4SLinus Torvalds 		break;
14791da177e4SLinus Torvalds 	default:
14801da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
14811da177e4SLinus Torvalds 			       	0);
14821da177e4SLinus Torvalds 		return check_condition_result;
14831da177e4SLinus Torvalds 	}
14841da177e4SLinus Torvalds 	if (msense_6)
14851da177e4SLinus Torvalds 		arr[0] = offset - 1;
14861da177e4SLinus Torvalds 	else {
14871da177e4SLinus Torvalds 		arr[0] = ((offset - 2) >> 8) & 0xff;
14881da177e4SLinus Torvalds 		arr[1] = (offset - 2) & 0xff;
14891da177e4SLinus Torvalds 	}
14901da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
14911da177e4SLinus Torvalds }
14921da177e4SLinus Torvalds 
1493c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
1494c65b1445SDouglas Gilbert 
1495c65b1445SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1496c65b1445SDouglas Gilbert 			    struct sdebug_dev_info * devip)
1497c65b1445SDouglas Gilbert {
1498c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1499c65b1445SDouglas Gilbert 	int param_len, res, errsts, mpage;
1500c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1501c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1502c65b1445SDouglas Gilbert 
1503c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1504c65b1445SDouglas Gilbert 		return errsts;
1505c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1506c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
1507c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
1508c65b1445SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1509c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1510c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1511c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
1512c65b1445SDouglas Gilbert 		return check_condition_result;
1513c65b1445SDouglas Gilbert 	}
1514c65b1445SDouglas Gilbert         res = fetch_to_dev_buffer(scp, arr, param_len);
1515c65b1445SDouglas Gilbert         if (-1 == res)
1516c65b1445SDouglas Gilbert                 return (DID_ERROR << 16);
1517c65b1445SDouglas Gilbert         else if ((res < param_len) &&
1518c65b1445SDouglas Gilbert                  (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1519c65b1445SDouglas Gilbert                 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1520c65b1445SDouglas Gilbert                        " IO sent=%d bytes\n", param_len, res);
1521c65b1445SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1522c65b1445SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
152323183910SDouglas Gilbert 	if (md_len > 2) {
1524c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1525c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_PARAM_LIST, 0);
1526c65b1445SDouglas Gilbert 		return check_condition_result;
1527c65b1445SDouglas Gilbert 	}
1528c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
1529c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
1530c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
1531c65b1445SDouglas Gilbert 	if (ps) {
1532c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1533c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_PARAM_LIST, 0);
1534c65b1445SDouglas Gilbert 		return check_condition_result;
1535c65b1445SDouglas Gilbert 	}
1536c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
1537c65b1445SDouglas Gilbert 	pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1538c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
1539c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
1540c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1541c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
1542c65b1445SDouglas Gilbert 		return check_condition_result;
1543c65b1445SDouglas Gilbert 	}
1544c65b1445SDouglas Gilbert 	switch (mpage) {
1545c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
1546c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
1547c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
1548c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
1549c65b1445SDouglas Gilbert 			scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1550c65b1445SDouglas Gilbert 			return 0;
1551c65b1445SDouglas Gilbert 		}
1552c65b1445SDouglas Gilbert 		break;
1553c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
1554c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
1555c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
1556c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
1557c65b1445SDouglas Gilbert 			return 0;
1558c65b1445SDouglas Gilbert 		}
1559c65b1445SDouglas Gilbert 		break;
1560c65b1445SDouglas Gilbert 	default:
1561c65b1445SDouglas Gilbert 		break;
1562c65b1445SDouglas Gilbert 	}
1563c65b1445SDouglas Gilbert 	mk_sense_buffer(devip, ILLEGAL_REQUEST,
1564c65b1445SDouglas Gilbert 			INVALID_FIELD_IN_PARAM_LIST, 0);
1565c65b1445SDouglas Gilbert 	return check_condition_result;
1566c65b1445SDouglas Gilbert }
1567c65b1445SDouglas Gilbert 
1568c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr)
1569c65b1445SDouglas Gilbert {
1570c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1571c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
1572c65b1445SDouglas Gilbert 		};
1573c65b1445SDouglas Gilbert 
1574c65b1445SDouglas Gilbert         memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1575c65b1445SDouglas Gilbert         return sizeof(temp_l_pg);
1576c65b1445SDouglas Gilbert }
1577c65b1445SDouglas Gilbert 
1578c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr)
1579c65b1445SDouglas Gilbert {
1580c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1581c65b1445SDouglas Gilbert 		};
1582c65b1445SDouglas Gilbert 
1583c65b1445SDouglas Gilbert         memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1584c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
1585c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
1586c65b1445SDouglas Gilbert 		arr[5] = 0xff;
1587c65b1445SDouglas Gilbert 	}
1588c65b1445SDouglas Gilbert         return sizeof(ie_l_pg);
1589c65b1445SDouglas Gilbert }
1590c65b1445SDouglas Gilbert 
1591c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
1592c65b1445SDouglas Gilbert 
1593c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp,
1594c65b1445SDouglas Gilbert                           struct sdebug_dev_info * devip)
1595c65b1445SDouglas Gilbert {
159623183910SDouglas Gilbert 	int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
1597c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1598c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1599c65b1445SDouglas Gilbert 
1600c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1601c65b1445SDouglas Gilbert 		return errsts;
1602c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1603c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
1604c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
1605c65b1445SDouglas Gilbert 	if (ppc || sp) {
1606c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1607c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
1608c65b1445SDouglas Gilbert 		return check_condition_result;
1609c65b1445SDouglas Gilbert 	}
1610c65b1445SDouglas Gilbert 	pcontrol = (cmd[2] & 0xc0) >> 6;
1611c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
161223183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
1613c65b1445SDouglas Gilbert 	alloc_len = (cmd[7] << 8) + cmd[8];
1614c65b1445SDouglas Gilbert 	arr[0] = pcode;
161523183910SDouglas Gilbert 	if (0 == subpcode) {
1616c65b1445SDouglas Gilbert 		switch (pcode) {
1617c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
1618c65b1445SDouglas Gilbert 			n = 4;
1619c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
1620c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
1621c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
1622c65b1445SDouglas Gilbert 			arr[3] = n - 4;
1623c65b1445SDouglas Gilbert 			break;
1624c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
1625c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
1626c65b1445SDouglas Gilbert 			break;
1627c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
1628c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
1629c65b1445SDouglas Gilbert 			break;
1630c65b1445SDouglas Gilbert 		default:
1631c65b1445SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
1632c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1633c65b1445SDouglas Gilbert 			return check_condition_result;
1634c65b1445SDouglas Gilbert 		}
163523183910SDouglas Gilbert 	} else if (0xff == subpcode) {
163623183910SDouglas Gilbert 		arr[0] |= 0x40;
163723183910SDouglas Gilbert 		arr[1] = subpcode;
163823183910SDouglas Gilbert 		switch (pcode) {
163923183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
164023183910SDouglas Gilbert 			n = 4;
164123183910SDouglas Gilbert 			arr[n++] = 0x0;
164223183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
164323183910SDouglas Gilbert 			arr[n++] = 0x0;
164423183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
164523183910SDouglas Gilbert 			arr[n++] = 0xd;
164623183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
164723183910SDouglas Gilbert 			arr[n++] = 0x2f;
164823183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
164923183910SDouglas Gilbert 			arr[3] = n - 4;
165023183910SDouglas Gilbert 			break;
165123183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
165223183910SDouglas Gilbert 			n = 4;
165323183910SDouglas Gilbert 			arr[n++] = 0xd;
165423183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
165523183910SDouglas Gilbert 			arr[3] = n - 4;
165623183910SDouglas Gilbert 			break;
165723183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
165823183910SDouglas Gilbert 			n = 4;
165923183910SDouglas Gilbert 			arr[n++] = 0x2f;
166023183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
166123183910SDouglas Gilbert 			arr[3] = n - 4;
166223183910SDouglas Gilbert 			break;
166323183910SDouglas Gilbert 		default:
166423183910SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
166523183910SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
166623183910SDouglas Gilbert 			return check_condition_result;
166723183910SDouglas Gilbert 		}
166823183910SDouglas Gilbert 	} else {
166923183910SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
167023183910SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
167123183910SDouglas Gilbert 		return check_condition_result;
167223183910SDouglas Gilbert 	}
1673c65b1445SDouglas Gilbert 	len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1674c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1675c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
1676c65b1445SDouglas Gilbert }
1677c65b1445SDouglas Gilbert 
167819789100SFUJITA Tomonori static int check_device_access_params(struct sdebug_dev_info *devi,
167919789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
16801da177e4SLinus Torvalds {
1681c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
168219789100SFUJITA Tomonori 		mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
16831da177e4SLinus Torvalds 		return check_condition_result;
16841da177e4SLinus Torvalds 	}
1685c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
1686c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
168719789100SFUJITA Tomonori 		mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
1688c65b1445SDouglas Gilbert 		return check_condition_result;
1689c65b1445SDouglas Gilbert 	}
169019789100SFUJITA Tomonori 	return 0;
169119789100SFUJITA Tomonori }
169219789100SFUJITA Tomonori 
1693a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
169419789100SFUJITA Tomonori static int do_device_access(struct scsi_cmnd *scmd,
169519789100SFUJITA Tomonori 			    struct sdebug_dev_info *devi,
169619789100SFUJITA Tomonori 			    unsigned long long lba, unsigned int num, int write)
169719789100SFUJITA Tomonori {
169819789100SFUJITA Tomonori 	int ret;
1699a361cc00SDarrick J. Wong 	unsigned long long block, rest = 0;
1700a4517511SAkinobu Mita 	struct scsi_data_buffer *sdb;
1701a4517511SAkinobu Mita 	enum dma_data_direction dir;
1702a4517511SAkinobu Mita 	size_t (*func)(struct scatterlist *, unsigned int, void *, size_t,
1703a4517511SAkinobu Mita 		       off_t);
170419789100SFUJITA Tomonori 
1705a4517511SAkinobu Mita 	if (write) {
1706a4517511SAkinobu Mita 		sdb = scsi_out(scmd);
1707a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
1708a4517511SAkinobu Mita 		func = sg_pcopy_to_buffer;
1709a4517511SAkinobu Mita 	} else {
1710a4517511SAkinobu Mita 		sdb = scsi_in(scmd);
1711a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
1712a4517511SAkinobu Mita 		func = sg_pcopy_from_buffer;
1713a4517511SAkinobu Mita 	}
1714a4517511SAkinobu Mita 
1715a4517511SAkinobu Mita 	if (!sdb->length)
1716a4517511SAkinobu Mita 		return 0;
1717a4517511SAkinobu Mita 	if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
1718a4517511SAkinobu Mita 		return -1;
171919789100SFUJITA Tomonori 
172019789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
172119789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
172219789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
172319789100SFUJITA Tomonori 
1724a4517511SAkinobu Mita 	ret = func(sdb->table.sgl, sdb->table.nents,
1725a4517511SAkinobu Mita 		   fake_storep + (block * scsi_debug_sector_size),
1726a4517511SAkinobu Mita 		   (num - rest) * scsi_debug_sector_size, 0);
1727a4517511SAkinobu Mita 	if (ret != (num - rest) * scsi_debug_sector_size)
1728a4517511SAkinobu Mita 		return ret;
1729a4517511SAkinobu Mita 
1730a4517511SAkinobu Mita 	if (rest) {
1731a4517511SAkinobu Mita 		ret += func(sdb->table.sgl, sdb->table.nents,
1732a4517511SAkinobu Mita 			    fake_storep, rest * scsi_debug_sector_size,
1733597136abSMartin K. Petersen 			    (num - rest) * scsi_debug_sector_size);
1734a4517511SAkinobu Mita 	}
173519789100SFUJITA Tomonori 
173619789100SFUJITA Tomonori 	return ret;
173719789100SFUJITA Tomonori }
173819789100SFUJITA Tomonori 
1739c6a44287SMartin K. Petersen static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
1740395cef03SMartin K. Petersen 			    unsigned int sectors, u32 ei_lba)
1741c6a44287SMartin K. Petersen {
1742c6a44287SMartin K. Petersen 	unsigned int i, resid;
1743c6a44287SMartin K. Petersen 	struct scatterlist *psgl;
1744c6a44287SMartin K. Petersen 	struct sd_dif_tuple *sdt;
1745c6a44287SMartin K. Petersen 	sector_t sector;
1746c6a44287SMartin K. Petersen 	sector_t tmp_sec = start_sec;
1747c6a44287SMartin K. Petersen 	void *paddr;
1748c6a44287SMartin K. Petersen 
1749c6a44287SMartin K. Petersen 	start_sec = do_div(tmp_sec, sdebug_store_sectors);
1750c6a44287SMartin K. Petersen 
1751c6a44287SMartin K. Petersen 	sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec));
1752c6a44287SMartin K. Petersen 
1753c6a44287SMartin K. Petersen 	for (i = 0 ; i < sectors ; i++) {
1754c6a44287SMartin K. Petersen 		u16 csum;
1755c6a44287SMartin K. Petersen 
1756c6a44287SMartin K. Petersen 		if (sdt[i].app_tag == 0xffff)
1757c6a44287SMartin K. Petersen 			continue;
1758c6a44287SMartin K. Petersen 
1759c6a44287SMartin K. Petersen 		sector = start_sec + i;
1760c6a44287SMartin K. Petersen 
1761c6a44287SMartin K. Petersen 		switch (scsi_debug_guard) {
1762c6a44287SMartin K. Petersen 		case 1:
1763c6a44287SMartin K. Petersen 			csum = ip_compute_csum(fake_storep +
1764c6a44287SMartin K. Petersen 					       sector * scsi_debug_sector_size,
1765c6a44287SMartin K. Petersen 					       scsi_debug_sector_size);
1766c6a44287SMartin K. Petersen 			break;
1767c6a44287SMartin K. Petersen 		case 0:
1768c6a44287SMartin K. Petersen 			csum = crc_t10dif(fake_storep +
1769c6a44287SMartin K. Petersen 					  sector * scsi_debug_sector_size,
1770c6a44287SMartin K. Petersen 					  scsi_debug_sector_size);
1771c6a44287SMartin K. Petersen 			csum = cpu_to_be16(csum);
1772c6a44287SMartin K. Petersen 			break;
1773c6a44287SMartin K. Petersen 		default:
1774c6a44287SMartin K. Petersen 			BUG();
1775c6a44287SMartin K. Petersen 		}
1776c6a44287SMartin K. Petersen 
1777c6a44287SMartin K. Petersen 		if (sdt[i].guard_tag != csum) {
1778c6a44287SMartin K. Petersen 			printk(KERN_ERR "%s: GUARD check failed on sector %lu" \
1779c6a44287SMartin K. Petersen 			       " rcvd 0x%04x, data 0x%04x\n", __func__,
1780c6a44287SMartin K. Petersen 			       (unsigned long)sector,
1781c6a44287SMartin K. Petersen 			       be16_to_cpu(sdt[i].guard_tag),
1782c6a44287SMartin K. Petersen 			       be16_to_cpu(csum));
1783c6a44287SMartin K. Petersen 			dif_errors++;
1784c6a44287SMartin K. Petersen 			return 0x01;
1785c6a44287SMartin K. Petersen 		}
1786c6a44287SMartin K. Petersen 
1787395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
1788c6a44287SMartin K. Petersen 		    be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) {
1789c6a44287SMartin K. Petersen 			printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1790c6a44287SMartin K. Petersen 			       __func__, (unsigned long)sector);
1791c6a44287SMartin K. Petersen 			dif_errors++;
1792c6a44287SMartin K. Petersen 			return 0x03;
1793c6a44287SMartin K. Petersen 		}
1794395cef03SMartin K. Petersen 
1795395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1796395cef03SMartin K. Petersen 		    be32_to_cpu(sdt[i].ref_tag) != ei_lba) {
1797395cef03SMartin K. Petersen 			printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1798395cef03SMartin K. Petersen 			       __func__, (unsigned long)sector);
1799395cef03SMartin K. Petersen 			dif_errors++;
1800395cef03SMartin K. Petersen 			return 0x03;
1801395cef03SMartin K. Petersen 		}
1802395cef03SMartin K. Petersen 
1803395cef03SMartin K. Petersen 		ei_lba++;
1804c6a44287SMartin K. Petersen 	}
1805c6a44287SMartin K. Petersen 
1806c6a44287SMartin K. Petersen 	resid = sectors * 8; /* Bytes of protection data to copy into sgl */
1807c6a44287SMartin K. Petersen 	sector = start_sec;
1808c6a44287SMartin K. Petersen 
1809c6a44287SMartin K. Petersen 	scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
1810c6a44287SMartin K. Petersen 		int len = min(psgl->length, resid);
1811c6a44287SMartin K. Petersen 
181277dfce07SCong Wang 		paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
1813c6a44287SMartin K. Petersen 		memcpy(paddr, dif_storep + dif_offset(sector), len);
1814c6a44287SMartin K. Petersen 
1815c6a44287SMartin K. Petersen 		sector += len >> 3;
1816c6a44287SMartin K. Petersen 		if (sector >= sdebug_store_sectors) {
1817c6a44287SMartin K. Petersen 			/* Force wrap */
1818c6a44287SMartin K. Petersen 			tmp_sec = sector;
1819c6a44287SMartin K. Petersen 			sector = do_div(tmp_sec, sdebug_store_sectors);
1820c6a44287SMartin K. Petersen 		}
1821c6a44287SMartin K. Petersen 		resid -= len;
182277dfce07SCong Wang 		kunmap_atomic(paddr);
1823c6a44287SMartin K. Petersen 	}
1824c6a44287SMartin K. Petersen 
1825c6a44287SMartin K. Petersen 	dix_reads++;
1826c6a44287SMartin K. Petersen 
1827c6a44287SMartin K. Petersen 	return 0;
1828c6a44287SMartin K. Petersen }
1829c6a44287SMartin K. Petersen 
183019789100SFUJITA Tomonori static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
1831395cef03SMartin K. Petersen 		     unsigned int num, struct sdebug_dev_info *devip,
1832395cef03SMartin K. Petersen 		     u32 ei_lba)
183319789100SFUJITA Tomonori {
183419789100SFUJITA Tomonori 	unsigned long iflags;
183519789100SFUJITA Tomonori 	int ret;
183619789100SFUJITA Tomonori 
183719789100SFUJITA Tomonori 	ret = check_device_access_params(devip, lba, num);
183819789100SFUJITA Tomonori 	if (ret)
183919789100SFUJITA Tomonori 		return ret;
184019789100SFUJITA Tomonori 
18411da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
184232f7ef73SDouglas Gilbert 	    (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
1843c65b1445SDouglas Gilbert 	    ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1844c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
184532f7ef73SDouglas Gilbert 		mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
1846c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
1847c65b1445SDouglas Gilbert 		if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1848c65b1445SDouglas Gilbert 			devip->sense_buff[0] |= 0x80;	/* Valid bit */
184932f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
185032f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
1851c65b1445SDouglas Gilbert 			devip->sense_buff[3] = (ret >> 24) & 0xff;
1852c65b1445SDouglas Gilbert 			devip->sense_buff[4] = (ret >> 16) & 0xff;
1853c65b1445SDouglas Gilbert 			devip->sense_buff[5] = (ret >> 8) & 0xff;
1854c65b1445SDouglas Gilbert 			devip->sense_buff[6] = ret & 0xff;
1855c65b1445SDouglas Gilbert 		}
1856a87e3a67SDouglas Gilbert 	        scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
18571da177e4SLinus Torvalds 		return check_condition_result;
18581da177e4SLinus Torvalds 	}
1859c6a44287SMartin K. Petersen 
1860c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
1861c6a44287SMartin K. Petersen 	if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
1862395cef03SMartin K. Petersen 		int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
1863c6a44287SMartin K. Petersen 
1864c6a44287SMartin K. Petersen 		if (prot_ret) {
1865c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
1866c6a44287SMartin K. Petersen 			return illegal_condition_result;
1867c6a44287SMartin K. Petersen 		}
1868c6a44287SMartin K. Petersen 	}
1869c6a44287SMartin K. Petersen 
18701da177e4SLinus Torvalds 	read_lock_irqsave(&atomic_rw, iflags);
187119789100SFUJITA Tomonori 	ret = do_device_access(SCpnt, devip, lba, num, 0);
18721da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
1873a4517511SAkinobu Mita 	if (ret == -1)
1874a4517511SAkinobu Mita 		return DID_ERROR << 16;
1875a4517511SAkinobu Mita 
1876a4517511SAkinobu Mita 	scsi_in(SCpnt)->resid = scsi_bufflen(SCpnt) - ret;
1877a4517511SAkinobu Mita 
1878a4517511SAkinobu Mita 	return 0;
18791da177e4SLinus Torvalds }
18801da177e4SLinus Torvalds 
1881c6a44287SMartin K. Petersen void dump_sector(unsigned char *buf, int len)
1882c6a44287SMartin K. Petersen {
1883c6a44287SMartin K. Petersen 	int i, j;
1884c6a44287SMartin K. Petersen 
1885c6a44287SMartin K. Petersen 	printk(KERN_ERR ">>> Sector Dump <<<\n");
1886c6a44287SMartin K. Petersen 
1887c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
1888c6a44287SMartin K. Petersen 		printk(KERN_ERR "%04d: ", i);
1889c6a44287SMartin K. Petersen 
1890c6a44287SMartin K. Petersen 		for (j = 0 ; j < 16 ; j++) {
1891c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
1892c6a44287SMartin K. Petersen 			if (c >= 0x20 && c < 0x7e)
1893c6a44287SMartin K. Petersen 				printk(" %c ", buf[i+j]);
1894c6a44287SMartin K. Petersen 			else
1895c6a44287SMartin K. Petersen 				printk("%02x ", buf[i+j]);
1896c6a44287SMartin K. Petersen 		}
1897c6a44287SMartin K. Petersen 
1898c6a44287SMartin K. Petersen 		printk("\n");
1899c6a44287SMartin K. Petersen 	}
1900c6a44287SMartin K. Petersen }
1901c6a44287SMartin K. Petersen 
1902c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
1903395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
1904c6a44287SMartin K. Petersen {
1905c6a44287SMartin K. Petersen 	int i, j, ret;
1906c6a44287SMartin K. Petersen 	struct sd_dif_tuple *sdt;
1907c6a44287SMartin K. Petersen 	struct scatterlist *dsgl = scsi_sglist(SCpnt);
1908c6a44287SMartin K. Petersen 	struct scatterlist *psgl = scsi_prot_sglist(SCpnt);
1909c6a44287SMartin K. Petersen 	void *daddr, *paddr;
1910c6a44287SMartin K. Petersen 	sector_t tmp_sec = start_sec;
1911c6a44287SMartin K. Petersen 	sector_t sector;
1912c6a44287SMartin K. Petersen 	int ppage_offset;
1913c6a44287SMartin K. Petersen 	unsigned short csum;
1914c6a44287SMartin K. Petersen 
1915c6a44287SMartin K. Petersen 	sector = do_div(tmp_sec, sdebug_store_sectors);
1916c6a44287SMartin K. Petersen 
1917c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
1918c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
1919c6a44287SMartin K. Petersen 
192077dfce07SCong Wang 	paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
1921c6a44287SMartin K. Petersen 	ppage_offset = 0;
1922c6a44287SMartin K. Petersen 
1923c6a44287SMartin K. Petersen 	/* For each data page */
1924c6a44287SMartin K. Petersen 	scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
192577dfce07SCong Wang 		daddr = kmap_atomic(sg_page(dsgl)) + dsgl->offset;
1926c6a44287SMartin K. Petersen 
1927c6a44287SMartin K. Petersen 		/* For each sector-sized chunk in data page */
1928c6a44287SMartin K. Petersen 		for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) {
1929c6a44287SMartin K. Petersen 
1930c6a44287SMartin K. Petersen 			/* If we're at the end of the current
1931c6a44287SMartin K. Petersen 			 * protection page advance to the next one
1932c6a44287SMartin K. Petersen 			 */
1933c6a44287SMartin K. Petersen 			if (ppage_offset >= psgl->length) {
193477dfce07SCong Wang 				kunmap_atomic(paddr);
1935c6a44287SMartin K. Petersen 				psgl = sg_next(psgl);
1936c6a44287SMartin K. Petersen 				BUG_ON(psgl == NULL);
193777dfce07SCong Wang 				paddr = kmap_atomic(sg_page(psgl))
1938c6a44287SMartin K. Petersen 					+ psgl->offset;
1939c6a44287SMartin K. Petersen 				ppage_offset = 0;
1940c6a44287SMartin K. Petersen 			}
1941c6a44287SMartin K. Petersen 
1942c6a44287SMartin K. Petersen 			sdt = paddr + ppage_offset;
1943c6a44287SMartin K. Petersen 
1944c6a44287SMartin K. Petersen 			switch (scsi_debug_guard) {
1945c6a44287SMartin K. Petersen 			case 1:
1946c6a44287SMartin K. Petersen 				csum = ip_compute_csum(daddr,
1947c6a44287SMartin K. Petersen 						       scsi_debug_sector_size);
1948c6a44287SMartin K. Petersen 				break;
1949c6a44287SMartin K. Petersen 			case 0:
1950c6a44287SMartin K. Petersen 				csum = cpu_to_be16(crc_t10dif(daddr,
1951c6a44287SMartin K. Petersen 						      scsi_debug_sector_size));
1952c6a44287SMartin K. Petersen 				break;
1953c6a44287SMartin K. Petersen 			default:
1954c6a44287SMartin K. Petersen 				BUG();
1955c6a44287SMartin K. Petersen 				ret = 0;
1956c6a44287SMartin K. Petersen 				goto out;
1957c6a44287SMartin K. Petersen 			}
1958c6a44287SMartin K. Petersen 
1959c6a44287SMartin K. Petersen 			if (sdt->guard_tag != csum) {
1960c6a44287SMartin K. Petersen 				printk(KERN_ERR
1961c6a44287SMartin K. Petersen 				       "%s: GUARD check failed on sector %lu " \
1962c6a44287SMartin K. Petersen 				       "rcvd 0x%04x, calculated 0x%04x\n",
1963c6a44287SMartin K. Petersen 				       __func__, (unsigned long)sector,
1964c6a44287SMartin K. Petersen 				       be16_to_cpu(sdt->guard_tag),
1965c6a44287SMartin K. Petersen 				       be16_to_cpu(csum));
1966c6a44287SMartin K. Petersen 				ret = 0x01;
1967c6a44287SMartin K. Petersen 				dump_sector(daddr, scsi_debug_sector_size);
1968c6a44287SMartin K. Petersen 				goto out;
1969c6a44287SMartin K. Petersen 			}
1970c6a44287SMartin K. Petersen 
1971395cef03SMartin K. Petersen 			if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
1972c6a44287SMartin K. Petersen 			    be32_to_cpu(sdt->ref_tag)
1973c6a44287SMartin K. Petersen 			    != (start_sec & 0xffffffff)) {
1974c6a44287SMartin K. Petersen 				printk(KERN_ERR
1975c6a44287SMartin K. Petersen 				       "%s: REF check failed on sector %lu\n",
1976c6a44287SMartin K. Petersen 				       __func__, (unsigned long)sector);
1977c6a44287SMartin K. Petersen 				ret = 0x03;
1978c6a44287SMartin K. Petersen 				dump_sector(daddr, scsi_debug_sector_size);
1979c6a44287SMartin K. Petersen 				goto out;
1980c6a44287SMartin K. Petersen 			}
1981c6a44287SMartin K. Petersen 
1982395cef03SMartin K. Petersen 			if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1983395cef03SMartin K. Petersen 			    be32_to_cpu(sdt->ref_tag) != ei_lba) {
1984395cef03SMartin K. Petersen 				printk(KERN_ERR
1985395cef03SMartin K. Petersen 				       "%s: REF check failed on sector %lu\n",
1986395cef03SMartin K. Petersen 				       __func__, (unsigned long)sector);
1987395cef03SMartin K. Petersen 				ret = 0x03;
1988395cef03SMartin K. Petersen 				dump_sector(daddr, scsi_debug_sector_size);
1989395cef03SMartin K. Petersen 				goto out;
1990395cef03SMartin K. Petersen 			}
1991395cef03SMartin K. Petersen 
1992c6a44287SMartin K. Petersen 			/* Would be great to copy this in bigger
1993c6a44287SMartin K. Petersen 			 * chunks.  However, for the sake of
1994c6a44287SMartin K. Petersen 			 * correctness we need to verify each sector
1995c6a44287SMartin K. Petersen 			 * before writing it to "stable" storage
1996c6a44287SMartin K. Petersen 			 */
1997c6a44287SMartin K. Petersen 			memcpy(dif_storep + dif_offset(sector), sdt, 8);
1998c6a44287SMartin K. Petersen 
1999c6a44287SMartin K. Petersen 			sector++;
2000c6a44287SMartin K. Petersen 
2001c6a44287SMartin K. Petersen 			if (sector == sdebug_store_sectors)
2002c6a44287SMartin K. Petersen 				sector = 0;	/* Force wrap */
2003c6a44287SMartin K. Petersen 
2004c6a44287SMartin K. Petersen 			start_sec++;
2005395cef03SMartin K. Petersen 			ei_lba++;
2006c6a44287SMartin K. Petersen 			daddr += scsi_debug_sector_size;
2007c6a44287SMartin K. Petersen 			ppage_offset += sizeof(struct sd_dif_tuple);
2008c6a44287SMartin K. Petersen 		}
2009c6a44287SMartin K. Petersen 
201077dfce07SCong Wang 		kunmap_atomic(daddr);
2011c6a44287SMartin K. Petersen 	}
2012c6a44287SMartin K. Petersen 
201377dfce07SCong Wang 	kunmap_atomic(paddr);
2014c6a44287SMartin K. Petersen 
2015c6a44287SMartin K. Petersen 	dix_writes++;
2016c6a44287SMartin K. Petersen 
2017c6a44287SMartin K. Petersen 	return 0;
2018c6a44287SMartin K. Petersen 
2019c6a44287SMartin K. Petersen out:
2020c6a44287SMartin K. Petersen 	dif_errors++;
202177dfce07SCong Wang 	kunmap_atomic(daddr);
202277dfce07SCong Wang 	kunmap_atomic(paddr);
2023c6a44287SMartin K. Petersen 	return ret;
2024c6a44287SMartin K. Petersen }
2025c6a44287SMartin K. Petersen 
2026b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
2027b90ebc3dSAkinobu Mita {
2028b90ebc3dSAkinobu Mita 	if (scsi_debug_unmap_alignment) {
2029b90ebc3dSAkinobu Mita 		lba += scsi_debug_unmap_granularity -
2030b90ebc3dSAkinobu Mita 			scsi_debug_unmap_alignment;
2031b90ebc3dSAkinobu Mita 	}
2032b90ebc3dSAkinobu Mita 	do_div(lba, scsi_debug_unmap_granularity);
2033b90ebc3dSAkinobu Mita 
2034b90ebc3dSAkinobu Mita 	return lba;
2035b90ebc3dSAkinobu Mita }
2036b90ebc3dSAkinobu Mita 
2037b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
2038b90ebc3dSAkinobu Mita {
2039b90ebc3dSAkinobu Mita 	return index * scsi_debug_unmap_granularity -
2040b90ebc3dSAkinobu Mita 		scsi_debug_unmap_alignment;
2041b90ebc3dSAkinobu Mita }
2042b90ebc3dSAkinobu Mita 
204344d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
204444d92694SMartin K. Petersen {
2045b90ebc3dSAkinobu Mita 	sector_t end;
2046b90ebc3dSAkinobu Mita 	unsigned int mapped;
2047b90ebc3dSAkinobu Mita 	unsigned long index;
2048b90ebc3dSAkinobu Mita 	unsigned long next;
204944d92694SMartin K. Petersen 
2050b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
2051b90ebc3dSAkinobu Mita 	mapped = test_bit(index, map_storep);
205244d92694SMartin K. Petersen 
205344d92694SMartin K. Petersen 	if (mapped)
2054b90ebc3dSAkinobu Mita 		next = find_next_zero_bit(map_storep, map_size, index);
205544d92694SMartin K. Petersen 	else
2056b90ebc3dSAkinobu Mita 		next = find_next_bit(map_storep, map_size, index);
205744d92694SMartin K. Petersen 
2058b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
205944d92694SMartin K. Petersen 	*num = end - lba;
206044d92694SMartin K. Petersen 
206144d92694SMartin K. Petersen 	return mapped;
206244d92694SMartin K. Petersen }
206344d92694SMartin K. Petersen 
206444d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
206544d92694SMartin K. Petersen {
206644d92694SMartin K. Petersen 	sector_t end = lba + len;
206744d92694SMartin K. Petersen 
206844d92694SMartin K. Petersen 	while (lba < end) {
2069b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
207044d92694SMartin K. Petersen 
2071b90ebc3dSAkinobu Mita 		if (index < map_size)
2072b90ebc3dSAkinobu Mita 			set_bit(index, map_storep);
207344d92694SMartin K. Petersen 
2074b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
207544d92694SMartin K. Petersen 	}
207644d92694SMartin K. Petersen }
207744d92694SMartin K. Petersen 
207844d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
207944d92694SMartin K. Petersen {
208044d92694SMartin K. Petersen 	sector_t end = lba + len;
208144d92694SMartin K. Petersen 
208244d92694SMartin K. Petersen 	while (lba < end) {
2083b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
208444d92694SMartin K. Petersen 
2085b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
2086b90ebc3dSAkinobu Mita 		    lba + scsi_debug_unmap_granularity <= end &&
2087b90ebc3dSAkinobu Mita 		    index < map_size) {
2088b90ebc3dSAkinobu Mita 			clear_bit(index, map_storep);
2089b90ebc3dSAkinobu Mita 			if (scsi_debug_lbprz) {
2090be1dd78dSEric Sandeen 				memset(fake_storep +
2091cc34a8e6SAkinobu Mita 				       lba * scsi_debug_sector_size, 0,
2092cc34a8e6SAkinobu Mita 				       scsi_debug_sector_size *
2093cc34a8e6SAkinobu Mita 				       scsi_debug_unmap_granularity);
2094be1dd78dSEric Sandeen 			}
2095b90ebc3dSAkinobu Mita 		}
2096b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
209744d92694SMartin K. Petersen 	}
209844d92694SMartin K. Petersen }
209944d92694SMartin K. Petersen 
2100c65b1445SDouglas Gilbert static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
2101395cef03SMartin K. Petersen 		      unsigned int num, struct sdebug_dev_info *devip,
2102395cef03SMartin K. Petersen 		      u32 ei_lba)
21031da177e4SLinus Torvalds {
21041da177e4SLinus Torvalds 	unsigned long iflags;
210519789100SFUJITA Tomonori 	int ret;
21061da177e4SLinus Torvalds 
210719789100SFUJITA Tomonori 	ret = check_device_access_params(devip, lba, num);
210819789100SFUJITA Tomonori 	if (ret)
210919789100SFUJITA Tomonori 		return ret;
21101da177e4SLinus Torvalds 
2111c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2112c6a44287SMartin K. Petersen 	if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
2113395cef03SMartin K. Petersen 		int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
2114c6a44287SMartin K. Petersen 
2115c6a44287SMartin K. Petersen 		if (prot_ret) {
2116c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
2117c6a44287SMartin K. Petersen 			return illegal_condition_result;
2118c6a44287SMartin K. Petersen 		}
2119c6a44287SMartin K. Petersen 	}
2120c6a44287SMartin K. Petersen 
21211da177e4SLinus Torvalds 	write_lock_irqsave(&atomic_rw, iflags);
212219789100SFUJITA Tomonori 	ret = do_device_access(SCpnt, devip, lba, num, 1);
21239ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
212444d92694SMartin K. Petersen 		map_region(lba, num);
21251da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
212619789100SFUJITA Tomonori 	if (-1 == ret)
21271da177e4SLinus Torvalds 		return (DID_ERROR << 16);
2128597136abSMartin K. Petersen 	else if ((ret < (num * scsi_debug_sector_size)) &&
21291da177e4SLinus Torvalds 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
2130c65b1445SDouglas Gilbert 		printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
2131597136abSMartin K. Petersen 		       " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
213244d92694SMartin K. Petersen 
21331da177e4SLinus Torvalds 	return 0;
21341da177e4SLinus Torvalds }
21351da177e4SLinus Torvalds 
213644d92694SMartin K. Petersen static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,
213744d92694SMartin K. Petersen 		      unsigned int num, struct sdebug_dev_info *devip,
213844d92694SMartin K. Petersen 			   u32 ei_lba, unsigned int unmap)
213944d92694SMartin K. Petersen {
214044d92694SMartin K. Petersen 	unsigned long iflags;
214144d92694SMartin K. Petersen 	unsigned long long i;
214244d92694SMartin K. Petersen 	int ret;
214344d92694SMartin K. Petersen 
214444d92694SMartin K. Petersen 	ret = check_device_access_params(devip, lba, num);
214544d92694SMartin K. Petersen 	if (ret)
214644d92694SMartin K. Petersen 		return ret;
214744d92694SMartin K. Petersen 
21485b94e232SMartin K. Petersen 	if (num > scsi_debug_write_same_length) {
21495b94e232SMartin K. Petersen 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
21505b94e232SMartin K. Petersen 				0);
21515b94e232SMartin K. Petersen 		return check_condition_result;
21525b94e232SMartin K. Petersen 	}
21535b94e232SMartin K. Petersen 
215444d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
215544d92694SMartin K. Petersen 
21569ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
215744d92694SMartin K. Petersen 		unmap_region(lba, num);
215844d92694SMartin K. Petersen 		goto out;
215944d92694SMartin K. Petersen 	}
216044d92694SMartin K. Petersen 
216144d92694SMartin K. Petersen 	/* Else fetch one logical block */
216244d92694SMartin K. Petersen 	ret = fetch_to_dev_buffer(scmd,
216344d92694SMartin K. Petersen 				  fake_storep + (lba * scsi_debug_sector_size),
216444d92694SMartin K. Petersen 				  scsi_debug_sector_size);
216544d92694SMartin K. Petersen 
216644d92694SMartin K. Petersen 	if (-1 == ret) {
216744d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
216844d92694SMartin K. Petersen 		return (DID_ERROR << 16);
216944d92694SMartin K. Petersen 	} else if ((ret < (num * scsi_debug_sector_size)) &&
217044d92694SMartin K. Petersen 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
217144d92694SMartin K. Petersen 		printk(KERN_INFO "scsi_debug: write same: cdb indicated=%u, "
217244d92694SMartin K. Petersen 		       " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
217344d92694SMartin K. Petersen 
217444d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
217544d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
217644d92694SMartin K. Petersen 		memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size),
217744d92694SMartin K. Petersen 		       fake_storep + (lba * scsi_debug_sector_size),
217844d92694SMartin K. Petersen 		       scsi_debug_sector_size);
217944d92694SMartin K. Petersen 
21809ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
218144d92694SMartin K. Petersen 		map_region(lba, num);
218244d92694SMartin K. Petersen out:
218344d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
218444d92694SMartin K. Petersen 
218544d92694SMartin K. Petersen 	return 0;
218644d92694SMartin K. Petersen }
218744d92694SMartin K. Petersen 
218844d92694SMartin K. Petersen struct unmap_block_desc {
218944d92694SMartin K. Petersen 	__be64	lba;
219044d92694SMartin K. Petersen 	__be32	blocks;
219144d92694SMartin K. Petersen 	__be32	__reserved;
219244d92694SMartin K. Petersen };
219344d92694SMartin K. Petersen 
219444d92694SMartin K. Petersen static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
219544d92694SMartin K. Petersen {
219644d92694SMartin K. Petersen 	unsigned char *buf;
219744d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
219844d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
219944d92694SMartin K. Petersen 	int ret;
220044d92694SMartin K. Petersen 
220144d92694SMartin K. Petersen 	ret = check_readiness(scmd, 1, devip);
220244d92694SMartin K. Petersen 	if (ret)
220344d92694SMartin K. Petersen 		return ret;
220444d92694SMartin K. Petersen 
220544d92694SMartin K. Petersen 	payload_len = get_unaligned_be16(&scmd->cmnd[7]);
220644d92694SMartin K. Petersen 	BUG_ON(scsi_bufflen(scmd) != payload_len);
220744d92694SMartin K. Petersen 
220844d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
220944d92694SMartin K. Petersen 
221044d92694SMartin K. Petersen 	buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC);
221144d92694SMartin K. Petersen 	if (!buf)
221244d92694SMartin K. Petersen 		return check_condition_result;
221344d92694SMartin K. Petersen 
221444d92694SMartin K. Petersen 	scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
221544d92694SMartin K. Petersen 
221644d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
221744d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
221844d92694SMartin K. Petersen 
221944d92694SMartin K. Petersen 	desc = (void *)&buf[8];
222044d92694SMartin K. Petersen 
222144d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
222244d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
222344d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
222444d92694SMartin K. Petersen 
222544d92694SMartin K. Petersen 		ret = check_device_access_params(devip, lba, num);
222644d92694SMartin K. Petersen 		if (ret)
222744d92694SMartin K. Petersen 			goto out;
222844d92694SMartin K. Petersen 
222944d92694SMartin K. Petersen 		unmap_region(lba, num);
223044d92694SMartin K. Petersen 	}
223144d92694SMartin K. Petersen 
223244d92694SMartin K. Petersen 	ret = 0;
223344d92694SMartin K. Petersen 
223444d92694SMartin K. Petersen out:
223544d92694SMartin K. Petersen 	kfree(buf);
223644d92694SMartin K. Petersen 
223744d92694SMartin K. Petersen 	return ret;
223844d92694SMartin K. Petersen }
223944d92694SMartin K. Petersen 
224044d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
224144d92694SMartin K. Petersen 
224244d92694SMartin K. Petersen static int resp_get_lba_status(struct scsi_cmnd * scmd,
224344d92694SMartin K. Petersen 			       struct sdebug_dev_info * devip)
224444d92694SMartin K. Petersen {
224544d92694SMartin K. Petersen 	unsigned long long lba;
224644d92694SMartin K. Petersen 	unsigned int alloc_len, mapped, num;
224744d92694SMartin K. Petersen 	unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN];
224844d92694SMartin K. Petersen 	int ret;
224944d92694SMartin K. Petersen 
225044d92694SMartin K. Petersen 	ret = check_readiness(scmd, 1, devip);
225144d92694SMartin K. Petersen 	if (ret)
225244d92694SMartin K. Petersen 		return ret;
225344d92694SMartin K. Petersen 
225444d92694SMartin K. Petersen 	lba = get_unaligned_be64(&scmd->cmnd[2]);
225544d92694SMartin K. Petersen 	alloc_len = get_unaligned_be32(&scmd->cmnd[10]);
225644d92694SMartin K. Petersen 
225744d92694SMartin K. Petersen 	if (alloc_len < 24)
225844d92694SMartin K. Petersen 		return 0;
225944d92694SMartin K. Petersen 
226044d92694SMartin K. Petersen 	ret = check_device_access_params(devip, lba, 1);
226144d92694SMartin K. Petersen 	if (ret)
226244d92694SMartin K. Petersen 		return ret;
226344d92694SMartin K. Petersen 
226444d92694SMartin K. Petersen 	mapped = map_state(lba, &num);
226544d92694SMartin K. Petersen 
226644d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
2267de13e965SDouglas Gilbert 	put_unaligned_be32(20, &arr[0]);	/* Parameter Data Length */
226844d92694SMartin K. Petersen 	put_unaligned_be64(lba, &arr[8]);	/* LBA */
226944d92694SMartin K. Petersen 	put_unaligned_be32(num, &arr[16]);	/* Number of blocks */
227044d92694SMartin K. Petersen 	arr[20] = !mapped;			/* mapped = 0, unmapped = 1 */
227144d92694SMartin K. Petersen 
227244d92694SMartin K. Petersen 	return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN);
227344d92694SMartin K. Petersen }
227444d92694SMartin K. Petersen 
2275c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256
22761da177e4SLinus Torvalds 
22771da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp,
22781da177e4SLinus Torvalds 			    struct sdebug_dev_info * devip)
22791da177e4SLinus Torvalds {
22801da177e4SLinus Torvalds 	unsigned int alloc_len;
2281c65b1445SDouglas Gilbert 	int lun_cnt, i, upper, num, n, wlun, lun;
22821da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
22831da177e4SLinus Torvalds 	int select_report = (int)cmd[2];
22841da177e4SLinus Torvalds 	struct scsi_lun *one_lun;
22851da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_RLUN_ARR_SZ];
2286c65b1445SDouglas Gilbert 	unsigned char * max_addr;
22871da177e4SLinus Torvalds 
22881da177e4SLinus Torvalds 	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
2289c65b1445SDouglas Gilbert 	if ((alloc_len < 4) || (select_report > 2)) {
22901da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
22911da177e4SLinus Torvalds 			       	0);
22921da177e4SLinus Torvalds 		return check_condition_result;
22931da177e4SLinus Torvalds 	}
22941da177e4SLinus Torvalds 	/* can produce response with up to 16k luns (lun 0 to lun 16383) */
22951da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
22961da177e4SLinus Torvalds 	lun_cnt = scsi_debug_max_luns;
2297c65b1445SDouglas Gilbert 	if (1 == select_report)
2298c65b1445SDouglas Gilbert 		lun_cnt = 0;
2299c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
2300c65b1445SDouglas Gilbert 		--lun_cnt;
2301c65b1445SDouglas Gilbert 	wlun = (select_report > 0) ? 1 : 0;
2302c65b1445SDouglas Gilbert 	num = lun_cnt + wlun;
2303c65b1445SDouglas Gilbert 	arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
2304c65b1445SDouglas Gilbert 	arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
2305c65b1445SDouglas Gilbert 	n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
2306c65b1445SDouglas Gilbert 			    sizeof(struct scsi_lun)), num);
2307c65b1445SDouglas Gilbert 	if (n < num) {
2308c65b1445SDouglas Gilbert 		wlun = 0;
2309c65b1445SDouglas Gilbert 		lun_cnt = n;
2310c65b1445SDouglas Gilbert 	}
23111da177e4SLinus Torvalds 	one_lun = (struct scsi_lun *) &arr[8];
2312c65b1445SDouglas Gilbert 	max_addr = arr + SDEBUG_RLUN_ARR_SZ;
2313c65b1445SDouglas Gilbert 	for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
2314c65b1445SDouglas Gilbert              ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
2315c65b1445SDouglas Gilbert 	     i++, lun++) {
2316c65b1445SDouglas Gilbert 		upper = (lun >> 8) & 0x3f;
23171da177e4SLinus Torvalds 		if (upper)
23181da177e4SLinus Torvalds 			one_lun[i].scsi_lun[0] =
23191da177e4SLinus Torvalds 			    (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
2320c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = lun & 0xff;
23211da177e4SLinus Torvalds 	}
2322c65b1445SDouglas Gilbert 	if (wlun) {
2323c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
2324c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
2325c65b1445SDouglas Gilbert 		i++;
2326c65b1445SDouglas Gilbert 	}
2327c65b1445SDouglas Gilbert 	alloc_len = (unsigned char *)(one_lun + i) - arr;
23281da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr,
23291da177e4SLinus Torvalds 				    min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
23301da177e4SLinus Torvalds }
23311da177e4SLinus Torvalds 
2332c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
2333c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
2334c639d14eSFUJITA Tomonori {
2335c639d14eSFUJITA Tomonori 	int i, j, ret = -1;
2336c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
2337c639d14eSFUJITA Tomonori 	unsigned int offset;
2338c639d14eSFUJITA Tomonori 	struct scatterlist *sg;
2339c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
2340c639d14eSFUJITA Tomonori 
2341c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
2342c639d14eSFUJITA Tomonori 	buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
2343c639d14eSFUJITA Tomonori 	if (!buf)
2344c639d14eSFUJITA Tomonori 		return ret;
2345c639d14eSFUJITA Tomonori 
234621a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
2347c639d14eSFUJITA Tomonori 
2348c639d14eSFUJITA Tomonori 	offset = 0;
2349c639d14eSFUJITA Tomonori 	for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
235077dfce07SCong Wang 		kaddr = (unsigned char *)kmap_atomic(sg_page(sg));
2351c639d14eSFUJITA Tomonori 		if (!kaddr)
2352c639d14eSFUJITA Tomonori 			goto out;
2353c639d14eSFUJITA Tomonori 
2354c639d14eSFUJITA Tomonori 		for (j = 0; j < sg->length; j++)
2355c639d14eSFUJITA Tomonori 			*(kaddr + sg->offset + j) ^= *(buf + offset + j);
2356c639d14eSFUJITA Tomonori 
2357c639d14eSFUJITA Tomonori 		offset += sg->length;
235877dfce07SCong Wang 		kunmap_atomic(kaddr);
2359c639d14eSFUJITA Tomonori 	}
2360c639d14eSFUJITA Tomonori 	ret = 0;
2361c639d14eSFUJITA Tomonori out:
2362c639d14eSFUJITA Tomonori 	kfree(buf);
2363c639d14eSFUJITA Tomonori 
2364c639d14eSFUJITA Tomonori 	return ret;
2365c639d14eSFUJITA Tomonori }
2366c639d14eSFUJITA Tomonori 
23671da177e4SLinus Torvalds /* When timer goes off this function is called. */
23681da177e4SLinus Torvalds static void timer_intr_handler(unsigned long indx)
23691da177e4SLinus Torvalds {
23701da177e4SLinus Torvalds 	struct sdebug_queued_cmd * sqcp;
23711da177e4SLinus Torvalds 	unsigned long iflags;
23721da177e4SLinus Torvalds 
237378d4e5a0SDouglas Gilbert 	if (indx >= scsi_debug_max_queue) {
23741da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
23751da177e4SLinus Torvalds 		       "large\n");
23761da177e4SLinus Torvalds 		return;
23771da177e4SLinus Torvalds 	}
23781da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
23791da177e4SLinus Torvalds 	sqcp = &queued_arr[(int)indx];
23801da177e4SLinus Torvalds 	if (! sqcp->in_use) {
23811da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
23821da177e4SLinus Torvalds 		       "interrupt\n");
23831da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
23841da177e4SLinus Torvalds 		return;
23851da177e4SLinus Torvalds 	}
23861da177e4SLinus Torvalds 	sqcp->in_use = 0;
23871da177e4SLinus Torvalds 	if (sqcp->done_funct) {
23881da177e4SLinus Torvalds 		sqcp->a_cmnd->result = sqcp->scsi_result;
23891da177e4SLinus Torvalds 		sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
23901da177e4SLinus Torvalds 	}
23911da177e4SLinus Torvalds 	sqcp->done_funct = NULL;
23921da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
23931da177e4SLinus Torvalds }
23941da177e4SLinus Torvalds 
23951da177e4SLinus Torvalds 
23968dea0d02SFUJITA Tomonori static struct sdebug_dev_info *
23978dea0d02SFUJITA Tomonori sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
23985cb2fc06SFUJITA Tomonori {
23995cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
24005cb2fc06SFUJITA Tomonori 
24015cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
24025cb2fc06SFUJITA Tomonori 	if (devip) {
24035cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
24045cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
24055cb2fc06SFUJITA Tomonori 	}
24065cb2fc06SFUJITA Tomonori 	return devip;
24075cb2fc06SFUJITA Tomonori }
24085cb2fc06SFUJITA Tomonori 
24091da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
24101da177e4SLinus Torvalds {
24111da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
24121da177e4SLinus Torvalds 	struct sdebug_dev_info * open_devip = NULL;
24131da177e4SLinus Torvalds 	struct sdebug_dev_info * devip =
24141da177e4SLinus Torvalds 			(struct sdebug_dev_info *)sdev->hostdata;
24151da177e4SLinus Torvalds 
24161da177e4SLinus Torvalds 	if (devip)
24171da177e4SLinus Torvalds 		return devip;
2418d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
24191da177e4SLinus Torvalds 	if (!sdbg_host) {
24201da177e4SLinus Torvalds                 printk(KERN_ERR "Host info NULL\n");
24211da177e4SLinus Torvalds 		return NULL;
24221da177e4SLinus Torvalds         }
24231da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
24241da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
24251da177e4SLinus Torvalds                     (devip->target == sdev->id) &&
24261da177e4SLinus Torvalds                     (devip->lun == sdev->lun))
24271da177e4SLinus Torvalds                         return devip;
24281da177e4SLinus Torvalds 		else {
24291da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
24301da177e4SLinus Torvalds 				open_devip = devip;
24311da177e4SLinus Torvalds 		}
24321da177e4SLinus Torvalds 	}
24335cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
24345cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
24355cb2fc06SFUJITA Tomonori 		if (!open_devip) {
24361da177e4SLinus Torvalds 			printk(KERN_ERR "%s: out of memory at line %d\n",
2437cadbd4a5SHarvey Harrison 				__func__, __LINE__);
24381da177e4SLinus Torvalds 			return NULL;
24391da177e4SLinus Torvalds 		}
24401da177e4SLinus Torvalds 	}
2441a75869d1SFUJITA Tomonori 
24421da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
24431da177e4SLinus Torvalds 	open_devip->target = sdev->id;
24441da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
24451da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
24461da177e4SLinus Torvalds 	open_devip->reset = 1;
24471da177e4SLinus Torvalds 	open_devip->used = 1;
24481da177e4SLinus Torvalds 	memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
24491da177e4SLinus Torvalds 	if (scsi_debug_dsense)
24501da177e4SLinus Torvalds 		open_devip->sense_buff[0] = 0x72;
24511da177e4SLinus Torvalds 	else {
24521da177e4SLinus Torvalds 		open_devip->sense_buff[0] = 0x70;
24531da177e4SLinus Torvalds 		open_devip->sense_buff[7] = 0xa;
24541da177e4SLinus Torvalds 	}
2455c65b1445SDouglas Gilbert 	if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2456c65b1445SDouglas Gilbert 		open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
2457a75869d1SFUJITA Tomonori 
24581da177e4SLinus Torvalds 	return open_devip;
24591da177e4SLinus Torvalds }
24601da177e4SLinus Torvalds 
24618dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
24621da177e4SLinus Torvalds {
24638dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
24648dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
24658dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
246675ad23bcSNick Piggin 	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
24678dea0d02SFUJITA Tomonori 	return 0;
24688dea0d02SFUJITA Tomonori }
24691da177e4SLinus Torvalds 
24708dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
24718dea0d02SFUJITA Tomonori {
24728dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip;
2473a34c4e98SFUJITA Tomonori 
24741da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
24758dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
24768dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
24778dea0d02SFUJITA Tomonori 	if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
24788dea0d02SFUJITA Tomonori 		sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
24798dea0d02SFUJITA Tomonori 	devip = devInfoReg(sdp);
24808dea0d02SFUJITA Tomonori 	if (NULL == devip)
24818dea0d02SFUJITA Tomonori 		return 1;	/* no resources, will be marked offline */
24828dea0d02SFUJITA Tomonori 	sdp->hostdata = devip;
24838dea0d02SFUJITA Tomonori 	if (sdp->host->cmd_per_lun)
24848dea0d02SFUJITA Tomonori 		scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
24858dea0d02SFUJITA Tomonori 					sdp->host->cmd_per_lun);
24868dea0d02SFUJITA Tomonori 	blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
248778d4e5a0SDouglas Gilbert 	if (scsi_debug_no_uld)
248878d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
24898dea0d02SFUJITA Tomonori 	return 0;
24908dea0d02SFUJITA Tomonori }
24918dea0d02SFUJITA Tomonori 
24928dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
24938dea0d02SFUJITA Tomonori {
24948dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
24958dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
24968dea0d02SFUJITA Tomonori 
24978dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
24988dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
24998dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
25008dea0d02SFUJITA Tomonori 	if (devip) {
250125985edcSLucas De Marchi 		/* make this slot available for re-use */
25028dea0d02SFUJITA Tomonori 		devip->used = 0;
25038dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
25048dea0d02SFUJITA Tomonori 	}
25058dea0d02SFUJITA Tomonori }
25068dea0d02SFUJITA Tomonori 
25078dea0d02SFUJITA Tomonori /* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
25088dea0d02SFUJITA Tomonori static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
25098dea0d02SFUJITA Tomonori {
25108dea0d02SFUJITA Tomonori 	unsigned long iflags;
25118dea0d02SFUJITA Tomonori 	int k;
25128dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
25138dea0d02SFUJITA Tomonori 
25148dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
251578d4e5a0SDouglas Gilbert 	for (k = 0; k < scsi_debug_max_queue; ++k) {
25168dea0d02SFUJITA Tomonori 		sqcp = &queued_arr[k];
25178dea0d02SFUJITA Tomonori 		if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
25188dea0d02SFUJITA Tomonori 			del_timer_sync(&sqcp->cmnd_timer);
25198dea0d02SFUJITA Tomonori 			sqcp->in_use = 0;
25208dea0d02SFUJITA Tomonori 			sqcp->a_cmnd = NULL;
25218dea0d02SFUJITA Tomonori 			break;
25228dea0d02SFUJITA Tomonori 		}
25238dea0d02SFUJITA Tomonori 	}
25248dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
252578d4e5a0SDouglas Gilbert 	return (k < scsi_debug_max_queue) ? 1 : 0;
25268dea0d02SFUJITA Tomonori }
25278dea0d02SFUJITA Tomonori 
25288dea0d02SFUJITA Tomonori /* Deletes (stops) timers of all queued commands */
25298dea0d02SFUJITA Tomonori static void stop_all_queued(void)
25308dea0d02SFUJITA Tomonori {
25318dea0d02SFUJITA Tomonori 	unsigned long iflags;
25328dea0d02SFUJITA Tomonori 	int k;
25338dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
25348dea0d02SFUJITA Tomonori 
25358dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
253678d4e5a0SDouglas Gilbert 	for (k = 0; k < scsi_debug_max_queue; ++k) {
25378dea0d02SFUJITA Tomonori 		sqcp = &queued_arr[k];
25388dea0d02SFUJITA Tomonori 		if (sqcp->in_use && sqcp->a_cmnd) {
25398dea0d02SFUJITA Tomonori 			del_timer_sync(&sqcp->cmnd_timer);
25408dea0d02SFUJITA Tomonori 			sqcp->in_use = 0;
25418dea0d02SFUJITA Tomonori 			sqcp->a_cmnd = NULL;
25428dea0d02SFUJITA Tomonori 		}
25438dea0d02SFUJITA Tomonori 	}
25448dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
25451da177e4SLinus Torvalds }
25461da177e4SLinus Torvalds 
25471da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
25481da177e4SLinus Torvalds {
25491da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25501da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: abort\n");
25511da177e4SLinus Torvalds 	++num_aborts;
25521da177e4SLinus Torvalds 	stop_queued_cmnd(SCpnt);
25531da177e4SLinus Torvalds 	return SUCCESS;
25541da177e4SLinus Torvalds }
25551da177e4SLinus Torvalds 
25561da177e4SLinus Torvalds static int scsi_debug_biosparam(struct scsi_device *sdev,
25571da177e4SLinus Torvalds 		struct block_device * bdev, sector_t capacity, int *info)
25581da177e4SLinus Torvalds {
25591da177e4SLinus Torvalds 	int res;
25601da177e4SLinus Torvalds 	unsigned char *buf;
25611da177e4SLinus Torvalds 
25621da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25631da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: biosparam\n");
25641da177e4SLinus Torvalds 	buf = scsi_bios_ptable(bdev);
25651da177e4SLinus Torvalds 	if (buf) {
25661da177e4SLinus Torvalds 		res = scsi_partsize(buf, capacity,
25671da177e4SLinus Torvalds 				    &info[2], &info[0], &info[1]);
25681da177e4SLinus Torvalds 		kfree(buf);
25691da177e4SLinus Torvalds 		if (! res)
25701da177e4SLinus Torvalds 			return res;
25711da177e4SLinus Torvalds 	}
25721da177e4SLinus Torvalds 	info[0] = sdebug_heads;
25731da177e4SLinus Torvalds 	info[1] = sdebug_sectors_per;
25741da177e4SLinus Torvalds 	info[2] = sdebug_cylinders_per;
25751da177e4SLinus Torvalds 	return 0;
25761da177e4SLinus Torvalds }
25771da177e4SLinus Torvalds 
25781da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
25791da177e4SLinus Torvalds {
25801da177e4SLinus Torvalds 	struct sdebug_dev_info * devip;
25811da177e4SLinus Torvalds 
25821da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25831da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: device_reset\n");
25841da177e4SLinus Torvalds 	++num_dev_resets;
25851da177e4SLinus Torvalds 	if (SCpnt) {
25861da177e4SLinus Torvalds 		devip = devInfoReg(SCpnt->device);
25871da177e4SLinus Torvalds 		if (devip)
25881da177e4SLinus Torvalds 			devip->reset = 1;
25891da177e4SLinus Torvalds 	}
25901da177e4SLinus Torvalds 	return SUCCESS;
25911da177e4SLinus Torvalds }
25921da177e4SLinus Torvalds 
25931da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
25941da177e4SLinus Torvalds {
25951da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
25961da177e4SLinus Torvalds         struct sdebug_dev_info * dev_info;
25971da177e4SLinus Torvalds         struct scsi_device * sdp;
25981da177e4SLinus Torvalds         struct Scsi_Host * hp;
25991da177e4SLinus Torvalds 
26001da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
26011da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: bus_reset\n");
26021da177e4SLinus Torvalds 	++num_bus_resets;
26031da177e4SLinus Torvalds 	if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
2604d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
26051da177e4SLinus Torvalds 		if (sdbg_host) {
26061da177e4SLinus Torvalds 			list_for_each_entry(dev_info,
26071da177e4SLinus Torvalds                                             &sdbg_host->dev_info_list,
26081da177e4SLinus Torvalds                                             dev_list)
26091da177e4SLinus Torvalds 				dev_info->reset = 1;
26101da177e4SLinus Torvalds 		}
26111da177e4SLinus Torvalds 	}
26121da177e4SLinus Torvalds 	return SUCCESS;
26131da177e4SLinus Torvalds }
26141da177e4SLinus Torvalds 
26151da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
26161da177e4SLinus Torvalds {
26171da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
26181da177e4SLinus Torvalds         struct sdebug_dev_info * dev_info;
26191da177e4SLinus Torvalds 
26201da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
26211da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: host_reset\n");
26221da177e4SLinus Torvalds 	++num_host_resets;
26231da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
26241da177e4SLinus Torvalds         list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
26251da177e4SLinus Torvalds                 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
26261da177e4SLinus Torvalds                                     dev_list)
26271da177e4SLinus Torvalds                         dev_info->reset = 1;
26281da177e4SLinus Torvalds         }
26291da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
26301da177e4SLinus Torvalds 	stop_all_queued();
26311da177e4SLinus Torvalds 	return SUCCESS;
26321da177e4SLinus Torvalds }
26331da177e4SLinus Torvalds 
26341da177e4SLinus Torvalds /* Initializes timers in queued array */
26351da177e4SLinus Torvalds static void __init init_all_queued(void)
26361da177e4SLinus Torvalds {
26371da177e4SLinus Torvalds 	unsigned long iflags;
26381da177e4SLinus Torvalds 	int k;
26391da177e4SLinus Torvalds 	struct sdebug_queued_cmd * sqcp;
26401da177e4SLinus Torvalds 
26411da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
264278d4e5a0SDouglas Gilbert 	for (k = 0; k < scsi_debug_max_queue; ++k) {
26431da177e4SLinus Torvalds 		sqcp = &queued_arr[k];
26441da177e4SLinus Torvalds 		init_timer(&sqcp->cmnd_timer);
26451da177e4SLinus Torvalds 		sqcp->in_use = 0;
26461da177e4SLinus Torvalds 		sqcp->a_cmnd = NULL;
26471da177e4SLinus Torvalds 	}
26481da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
26491da177e4SLinus Torvalds }
26501da177e4SLinus Torvalds 
2651f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
26525f2578e5SFUJITA Tomonori 				      unsigned long store_size)
26531da177e4SLinus Torvalds {
26541da177e4SLinus Torvalds 	struct partition * pp;
26551da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
26561da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
26571da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
26581da177e4SLinus Torvalds 
26591da177e4SLinus Torvalds 	/* assume partition table already zeroed */
2660f58b0efbSFUJITA Tomonori 	if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
26611da177e4SLinus Torvalds 		return;
26621da177e4SLinus Torvalds 	if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
26631da177e4SLinus Torvalds 		scsi_debug_num_parts = SDEBUG_MAX_PARTS;
26641da177e4SLinus Torvalds 		printk(KERN_WARNING "scsi_debug:build_parts: reducing "
26651da177e4SLinus Torvalds 				    "partitions to %d\n", SDEBUG_MAX_PARTS);
26661da177e4SLinus Torvalds 	}
2667c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
26681da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
26691da177e4SLinus Torvalds 			   / scsi_debug_num_parts;
26701da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
26711da177e4SLinus Torvalds         starts[0] = sdebug_sectors_per;
26721da177e4SLinus Torvalds 	for (k = 1; k < scsi_debug_num_parts; ++k)
26731da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
26741da177e4SLinus Torvalds 			    * heads_by_sects;
26751da177e4SLinus Torvalds 	starts[scsi_debug_num_parts] = num_sectors;
26761da177e4SLinus Torvalds 	starts[scsi_debug_num_parts + 1] = 0;
26771da177e4SLinus Torvalds 
26781da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
26791da177e4SLinus Torvalds 	ramp[511] = 0xAA;
26801da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
26811da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
26821da177e4SLinus Torvalds 		start_sec = starts[k];
26831da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
26841da177e4SLinus Torvalds 		pp->boot_ind = 0;
26851da177e4SLinus Torvalds 
26861da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
26871da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
26881da177e4SLinus Torvalds 			   / sdebug_sectors_per;
26891da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
26901da177e4SLinus Torvalds 
26911da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
26921da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
26931da177e4SLinus Torvalds 			       / sdebug_sectors_per;
26941da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
26951da177e4SLinus Torvalds 
26961da177e4SLinus Torvalds 		pp->start_sect = start_sec;
26971da177e4SLinus Torvalds 		pp->nr_sects = end_sec - start_sec + 1;
26981da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
26991da177e4SLinus Torvalds 	}
27001da177e4SLinus Torvalds }
27011da177e4SLinus Torvalds 
27021da177e4SLinus Torvalds static int schedule_resp(struct scsi_cmnd * cmnd,
27031da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip,
27041da177e4SLinus Torvalds 			 done_funct_t done, int scsi_result, int delta_jiff)
27051da177e4SLinus Torvalds {
27061da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
27071da177e4SLinus Torvalds 		if (scsi_result) {
27081da177e4SLinus Torvalds 			struct scsi_device * sdp = cmnd->device;
27091da177e4SLinus Torvalds 
2710c65b1445SDouglas Gilbert 			printk(KERN_INFO "scsi_debug:    <%u %u %u %u> "
2711c65b1445SDouglas Gilbert 			       "non-zero result=0x%x\n", sdp->host->host_no,
2712c65b1445SDouglas Gilbert 			       sdp->channel, sdp->id, sdp->lun, scsi_result);
27131da177e4SLinus Torvalds 		}
27141da177e4SLinus Torvalds 	}
27151da177e4SLinus Torvalds 	if (cmnd && devip) {
27161da177e4SLinus Torvalds 		/* simulate autosense by this driver */
27171da177e4SLinus Torvalds 		if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
27181da177e4SLinus Torvalds 			memcpy(cmnd->sense_buffer, devip->sense_buff,
27191da177e4SLinus Torvalds 			       (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
27201da177e4SLinus Torvalds 			       SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
27211da177e4SLinus Torvalds 	}
27221da177e4SLinus Torvalds 	if (delta_jiff <= 0) {
27231da177e4SLinus Torvalds 		if (cmnd)
27241da177e4SLinus Torvalds 			cmnd->result = scsi_result;
27251da177e4SLinus Torvalds 		if (done)
27261da177e4SLinus Torvalds 			done(cmnd);
27271da177e4SLinus Torvalds 		return 0;
27281da177e4SLinus Torvalds 	} else {
27291da177e4SLinus Torvalds 		unsigned long iflags;
27301da177e4SLinus Torvalds 		int k;
27311da177e4SLinus Torvalds 		struct sdebug_queued_cmd * sqcp = NULL;
27321da177e4SLinus Torvalds 
27331da177e4SLinus Torvalds 		spin_lock_irqsave(&queued_arr_lock, iflags);
273478d4e5a0SDouglas Gilbert 		for (k = 0; k < scsi_debug_max_queue; ++k) {
27351da177e4SLinus Torvalds 			sqcp = &queued_arr[k];
27361da177e4SLinus Torvalds 			if (! sqcp->in_use)
27371da177e4SLinus Torvalds 				break;
27381da177e4SLinus Torvalds 		}
273978d4e5a0SDouglas Gilbert 		if (k >= scsi_debug_max_queue) {
27401da177e4SLinus Torvalds 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
27411da177e4SLinus Torvalds 			printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
27421da177e4SLinus Torvalds 			return 1;	/* report busy to mid level */
27431da177e4SLinus Torvalds 		}
27441da177e4SLinus Torvalds 		sqcp->in_use = 1;
27451da177e4SLinus Torvalds 		sqcp->a_cmnd = cmnd;
27461da177e4SLinus Torvalds 		sqcp->scsi_result = scsi_result;
27471da177e4SLinus Torvalds 		sqcp->done_funct = done;
27481da177e4SLinus Torvalds 		sqcp->cmnd_timer.function = timer_intr_handler;
27491da177e4SLinus Torvalds 		sqcp->cmnd_timer.data = k;
27501da177e4SLinus Torvalds 		sqcp->cmnd_timer.expires = jiffies + delta_jiff;
27511da177e4SLinus Torvalds 		add_timer(&sqcp->cmnd_timer);
27521da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
27531da177e4SLinus Torvalds 		if (cmnd)
27541da177e4SLinus Torvalds 			cmnd->result = 0;
27551da177e4SLinus Torvalds 		return 0;
27561da177e4SLinus Torvalds 	}
27571da177e4SLinus Torvalds }
275823183910SDouglas Gilbert /* Note: The following macros create attribute files in the
275923183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
276023183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
276123183910SDouglas Gilbert    as it can when the corresponding attribute in the
276223183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
276323183910SDouglas Gilbert  */
2764c65b1445SDouglas Gilbert module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
27655b94e232SMartin K. Petersen module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
2766c65b1445SDouglas Gilbert module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2767c65b1445SDouglas Gilbert module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
27685b94e232SMartin K. Petersen module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
27695b94e232SMartin K. Petersen module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
2770c65b1445SDouglas Gilbert module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2771c65b1445SDouglas Gilbert module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
277223183910SDouglas Gilbert module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
27735b94e232SMartin K. Petersen module_param_named(guard, scsi_debug_guard, int, S_IRUGO);
27745b94e232SMartin K. Petersen module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO);
27755b94e232SMartin K. Petersen module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO);
27765b94e232SMartin K. Petersen module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO);
2777be1dd78dSEric Sandeen module_param_named(lbprz, scsi_debug_lbprz, int, S_IRUGO);
27785b94e232SMartin K. Petersen module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
2779c65b1445SDouglas Gilbert module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
278078d4e5a0SDouglas Gilbert module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);
2781c65b1445SDouglas Gilbert module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
278278d4e5a0SDouglas Gilbert module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);
2783c65b1445SDouglas Gilbert module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2784c65b1445SDouglas Gilbert module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
27855b94e232SMartin K. Petersen module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO);
2786c65b1445SDouglas Gilbert module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
27875b94e232SMartin K. Petersen module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
2788c65b1445SDouglas Gilbert module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2789d986788bSMartin Pitt module_param_named(removable, scsi_debug_removable, bool, S_IRUGO | S_IWUSR);
2790c65b1445SDouglas Gilbert module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
27915b94e232SMartin K. Petersen module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
27925b94e232SMartin K. Petersen module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
27935b94e232SMartin K. Petersen module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
27945b94e232SMartin K. Petersen module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
27955b94e232SMartin K. Petersen module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
2796c65b1445SDouglas Gilbert module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
279723183910SDouglas Gilbert module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
279823183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
27995b94e232SMartin K. Petersen module_param_named(write_same_length, scsi_debug_write_same_length, int,
28005b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
28011da177e4SLinus Torvalds 
28021da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
28031da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
28041da177e4SLinus Torvalds MODULE_LICENSE("GPL");
28051da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION);
28061da177e4SLinus Torvalds 
28071da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
28085b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
28091da177e4SLinus Torvalds MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
2810c65b1445SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
28115b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
28125b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
2813c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
2814beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
281523183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
28165b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
28175b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
28185b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
28195b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
2820be1dd78dSEric Sandeen MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
28215b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
2822c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
282378d4e5a0SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to 255(def))");
2824c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
282578d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
28261da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
2827c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
28285b94e232SMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
28296f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
28305b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
28311da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2832d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
28331da177e4SLinus Torvalds MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
2834ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
28355b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
28365b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
28376014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
28386014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
28395b94e232SMartin K. Petersen MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
28405b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
28415b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
28421da177e4SLinus Torvalds 
28431da177e4SLinus Torvalds static char sdebug_info[256];
28441da177e4SLinus Torvalds 
28451da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp)
28461da177e4SLinus Torvalds {
28471da177e4SLinus Torvalds 	sprintf(sdebug_info, "scsi_debug, version %s [%s], "
28481da177e4SLinus Torvalds 		"dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
28491da177e4SLinus Torvalds 		scsi_debug_version_date, scsi_debug_dev_size_mb,
28501da177e4SLinus Torvalds 		scsi_debug_opts);
28511da177e4SLinus Torvalds 	return sdebug_info;
28521da177e4SLinus Torvalds }
28531da177e4SLinus Torvalds 
28541da177e4SLinus Torvalds /* scsi_debug_proc_info
28551da177e4SLinus Torvalds  * Used if the driver currently has no own support for /proc/scsi
28561da177e4SLinus Torvalds  */
2857c8ed555aSAl Viro static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, int length)
28581da177e4SLinus Torvalds {
28591da177e4SLinus Torvalds 	char arr[16];
2860c8ed555aSAl Viro 	int opts;
28611da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
28621da177e4SLinus Torvalds 
28631da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
28641da177e4SLinus Torvalds 		return -EACCES;
28651da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
28661da177e4SLinus Torvalds 	arr[minLen] = '\0';
2867c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
28681da177e4SLinus Torvalds 		return -EINVAL;
2869c8ed555aSAl Viro 	scsi_debug_opts = opts;
28701da177e4SLinus Torvalds 	if (scsi_debug_every_nth != 0)
28711da177e4SLinus Torvalds 		scsi_debug_cmnd_count = 0;
28721da177e4SLinus Torvalds 	return length;
28731da177e4SLinus Torvalds }
2874c8ed555aSAl Viro 
2875c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
2876c8ed555aSAl Viro {
2877c8ed555aSAl Viro 	seq_printf(m, "scsi_debug adapter driver, version "
28781da177e4SLinus Torvalds 	    "%s [%s]\n"
28791da177e4SLinus Torvalds 	    "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
28801da177e4SLinus Torvalds 	    "every_nth=%d(curr:%d)\n"
28811da177e4SLinus Torvalds 	    "delay=%d, max_luns=%d, scsi_level=%d\n"
28821da177e4SLinus Torvalds 	    "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
28831da177e4SLinus Torvalds 	    "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2884c6a44287SMartin K. Petersen 	    "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n",
28851da177e4SLinus Torvalds 	    SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
28861da177e4SLinus Torvalds 	    scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
28871da177e4SLinus Torvalds 	    scsi_debug_cmnd_count, scsi_debug_delay,
28881da177e4SLinus Torvalds 	    scsi_debug_max_luns, scsi_debug_scsi_level,
2889597136abSMartin K. Petersen 	    scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
2890597136abSMartin K. Petersen 	    sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
2891c6a44287SMartin K. Petersen 	    num_host_resets, dix_reads, dix_writes, dif_errors);
2892c8ed555aSAl Viro 	return 0;
28931da177e4SLinus Torvalds }
28941da177e4SLinus Torvalds 
28951da177e4SLinus Torvalds static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
28961da177e4SLinus Torvalds {
28971da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
28981da177e4SLinus Torvalds }
28991da177e4SLinus Torvalds 
29001da177e4SLinus Torvalds static ssize_t sdebug_delay_store(struct device_driver * ddp,
29011da177e4SLinus Torvalds 				  const char * buf, size_t count)
29021da177e4SLinus Torvalds {
29031da177e4SLinus Torvalds         int delay;
29041da177e4SLinus Torvalds 	char work[20];
29051da177e4SLinus Torvalds 
29061da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
29071da177e4SLinus Torvalds 		if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
29081da177e4SLinus Torvalds 			scsi_debug_delay = delay;
29091da177e4SLinus Torvalds 			return count;
29101da177e4SLinus Torvalds 		}
29111da177e4SLinus Torvalds 	}
29121da177e4SLinus Torvalds 	return -EINVAL;
29131da177e4SLinus Torvalds }
29141da177e4SLinus Torvalds DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
29151da177e4SLinus Torvalds 	    sdebug_delay_store);
29161da177e4SLinus Torvalds 
29171da177e4SLinus Torvalds static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
29181da177e4SLinus Torvalds {
29191da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
29201da177e4SLinus Torvalds }
29211da177e4SLinus Torvalds 
29221da177e4SLinus Torvalds static ssize_t sdebug_opts_store(struct device_driver * ddp,
29231da177e4SLinus Torvalds 				 const char * buf, size_t count)
29241da177e4SLinus Torvalds {
29251da177e4SLinus Torvalds         int opts;
29261da177e4SLinus Torvalds 	char work[20];
29271da177e4SLinus Torvalds 
29281da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
29291da177e4SLinus Torvalds 		if (0 == strnicmp(work,"0x", 2)) {
29301da177e4SLinus Torvalds 			if (1 == sscanf(&work[2], "%x", &opts))
29311da177e4SLinus Torvalds 				goto opts_done;
29321da177e4SLinus Torvalds 		} else {
29331da177e4SLinus Torvalds 			if (1 == sscanf(work, "%d", &opts))
29341da177e4SLinus Torvalds 				goto opts_done;
29351da177e4SLinus Torvalds 		}
29361da177e4SLinus Torvalds 	}
29371da177e4SLinus Torvalds 	return -EINVAL;
29381da177e4SLinus Torvalds opts_done:
29391da177e4SLinus Torvalds 	scsi_debug_opts = opts;
29401da177e4SLinus Torvalds 	scsi_debug_cmnd_count = 0;
29411da177e4SLinus Torvalds 	return count;
29421da177e4SLinus Torvalds }
29431da177e4SLinus Torvalds DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
29441da177e4SLinus Torvalds 	    sdebug_opts_store);
29451da177e4SLinus Torvalds 
29461da177e4SLinus Torvalds static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
29471da177e4SLinus Torvalds {
29481da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
29491da177e4SLinus Torvalds }
29501da177e4SLinus Torvalds static ssize_t sdebug_ptype_store(struct device_driver * ddp,
29511da177e4SLinus Torvalds 				  const char * buf, size_t count)
29521da177e4SLinus Torvalds {
29531da177e4SLinus Torvalds         int n;
29541da177e4SLinus Torvalds 
29551da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
29561da177e4SLinus Torvalds 		scsi_debug_ptype = n;
29571da177e4SLinus Torvalds 		return count;
29581da177e4SLinus Torvalds 	}
29591da177e4SLinus Torvalds 	return -EINVAL;
29601da177e4SLinus Torvalds }
29611da177e4SLinus Torvalds DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
29621da177e4SLinus Torvalds 
29631da177e4SLinus Torvalds static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
29641da177e4SLinus Torvalds {
29651da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
29661da177e4SLinus Torvalds }
29671da177e4SLinus Torvalds static ssize_t sdebug_dsense_store(struct device_driver * ddp,
29681da177e4SLinus Torvalds 				  const char * buf, size_t count)
29691da177e4SLinus Torvalds {
29701da177e4SLinus Torvalds         int n;
29711da177e4SLinus Torvalds 
29721da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
29731da177e4SLinus Torvalds 		scsi_debug_dsense = n;
29741da177e4SLinus Torvalds 		return count;
29751da177e4SLinus Torvalds 	}
29761da177e4SLinus Torvalds 	return -EINVAL;
29771da177e4SLinus Torvalds }
29781da177e4SLinus Torvalds DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
29791da177e4SLinus Torvalds 	    sdebug_dsense_store);
29801da177e4SLinus Torvalds 
298123183910SDouglas Gilbert static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
298223183910SDouglas Gilbert {
298323183910SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
298423183910SDouglas Gilbert }
298523183910SDouglas Gilbert static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
298623183910SDouglas Gilbert 				    const char * buf, size_t count)
298723183910SDouglas Gilbert {
298823183910SDouglas Gilbert         int n;
298923183910SDouglas Gilbert 
299023183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
299123183910SDouglas Gilbert 		scsi_debug_fake_rw = n;
299223183910SDouglas Gilbert 		return count;
299323183910SDouglas Gilbert 	}
299423183910SDouglas Gilbert 	return -EINVAL;
299523183910SDouglas Gilbert }
299623183910SDouglas Gilbert DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
299723183910SDouglas Gilbert 	    sdebug_fake_rw_store);
299823183910SDouglas Gilbert 
2999c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
3000c65b1445SDouglas Gilbert {
3001c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
3002c65b1445SDouglas Gilbert }
3003c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
3004c65b1445SDouglas Gilbert 				     const char * buf, size_t count)
3005c65b1445SDouglas Gilbert {
3006c65b1445SDouglas Gilbert         int n;
3007c65b1445SDouglas Gilbert 
3008c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3009c65b1445SDouglas Gilbert 		scsi_debug_no_lun_0 = n;
3010c65b1445SDouglas Gilbert 		return count;
3011c65b1445SDouglas Gilbert 	}
3012c65b1445SDouglas Gilbert 	return -EINVAL;
3013c65b1445SDouglas Gilbert }
3014c65b1445SDouglas Gilbert DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
3015c65b1445SDouglas Gilbert 	    sdebug_no_lun_0_store);
3016c65b1445SDouglas Gilbert 
30171da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
30181da177e4SLinus Torvalds {
30191da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
30201da177e4SLinus Torvalds }
30211da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
30221da177e4SLinus Torvalds 				     const char * buf, size_t count)
30231da177e4SLinus Torvalds {
30241da177e4SLinus Torvalds         int n;
30251da177e4SLinus Torvalds 
30261da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
30271da177e4SLinus Torvalds 		scsi_debug_num_tgts = n;
30281da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
30291da177e4SLinus Torvalds 		return count;
30301da177e4SLinus Torvalds 	}
30311da177e4SLinus Torvalds 	return -EINVAL;
30321da177e4SLinus Torvalds }
30331da177e4SLinus Torvalds DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
30341da177e4SLinus Torvalds 	    sdebug_num_tgts_store);
30351da177e4SLinus Torvalds 
30361da177e4SLinus Torvalds static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
30371da177e4SLinus Torvalds {
30381da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
30391da177e4SLinus Torvalds }
30401da177e4SLinus Torvalds DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
30411da177e4SLinus Torvalds 
30421da177e4SLinus Torvalds static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
30431da177e4SLinus Torvalds {
30441da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
30451da177e4SLinus Torvalds }
30461da177e4SLinus Torvalds DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
30471da177e4SLinus Torvalds 
30481da177e4SLinus Torvalds static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
30491da177e4SLinus Torvalds {
30501da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
30511da177e4SLinus Torvalds }
30521da177e4SLinus Torvalds static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
30531da177e4SLinus Torvalds 				      const char * buf, size_t count)
30541da177e4SLinus Torvalds {
30551da177e4SLinus Torvalds         int nth;
30561da177e4SLinus Torvalds 
30571da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
30581da177e4SLinus Torvalds 		scsi_debug_every_nth = nth;
30591da177e4SLinus Torvalds 		scsi_debug_cmnd_count = 0;
30601da177e4SLinus Torvalds 		return count;
30611da177e4SLinus Torvalds 	}
30621da177e4SLinus Torvalds 	return -EINVAL;
30631da177e4SLinus Torvalds }
30641da177e4SLinus Torvalds DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
30651da177e4SLinus Torvalds 	    sdebug_every_nth_store);
30661da177e4SLinus Torvalds 
30671da177e4SLinus Torvalds static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
30681da177e4SLinus Torvalds {
30691da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
30701da177e4SLinus Torvalds }
30711da177e4SLinus Torvalds static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
30721da177e4SLinus Torvalds 				     const char * buf, size_t count)
30731da177e4SLinus Torvalds {
30741da177e4SLinus Torvalds         int n;
30751da177e4SLinus Torvalds 
30761da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
30771da177e4SLinus Torvalds 		scsi_debug_max_luns = n;
30781da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
30791da177e4SLinus Torvalds 		return count;
30801da177e4SLinus Torvalds 	}
30811da177e4SLinus Torvalds 	return -EINVAL;
30821da177e4SLinus Torvalds }
30831da177e4SLinus Torvalds DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
30841da177e4SLinus Torvalds 	    sdebug_max_luns_store);
30851da177e4SLinus Torvalds 
308678d4e5a0SDouglas Gilbert static ssize_t sdebug_max_queue_show(struct device_driver * ddp, char * buf)
308778d4e5a0SDouglas Gilbert {
308878d4e5a0SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue);
308978d4e5a0SDouglas Gilbert }
309078d4e5a0SDouglas Gilbert static ssize_t sdebug_max_queue_store(struct device_driver * ddp,
309178d4e5a0SDouglas Gilbert 				      const char * buf, size_t count)
309278d4e5a0SDouglas Gilbert {
309378d4e5a0SDouglas Gilbert         int n;
309478d4e5a0SDouglas Gilbert 
309578d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
309678d4e5a0SDouglas Gilbert 	    (n <= SCSI_DEBUG_CANQUEUE)) {
309778d4e5a0SDouglas Gilbert 		scsi_debug_max_queue = n;
309878d4e5a0SDouglas Gilbert 		return count;
309978d4e5a0SDouglas Gilbert 	}
310078d4e5a0SDouglas Gilbert 	return -EINVAL;
310178d4e5a0SDouglas Gilbert }
310278d4e5a0SDouglas Gilbert DRIVER_ATTR(max_queue, S_IRUGO | S_IWUSR, sdebug_max_queue_show,
310378d4e5a0SDouglas Gilbert 	    sdebug_max_queue_store);
310478d4e5a0SDouglas Gilbert 
310578d4e5a0SDouglas Gilbert static ssize_t sdebug_no_uld_show(struct device_driver * ddp, char * buf)
310678d4e5a0SDouglas Gilbert {
310778d4e5a0SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld);
310878d4e5a0SDouglas Gilbert }
310978d4e5a0SDouglas Gilbert DRIVER_ATTR(no_uld, S_IRUGO, sdebug_no_uld_show, NULL);
311078d4e5a0SDouglas Gilbert 
31111da177e4SLinus Torvalds static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
31121da177e4SLinus Torvalds {
31131da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
31141da177e4SLinus Torvalds }
31151da177e4SLinus Torvalds DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
31161da177e4SLinus Torvalds 
3117c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
3118c65b1445SDouglas Gilbert {
3119c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
3120c65b1445SDouglas Gilbert }
3121c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
3122c65b1445SDouglas Gilbert 				       const char * buf, size_t count)
3123c65b1445SDouglas Gilbert {
3124c65b1445SDouglas Gilbert         int n;
3125c65b1445SDouglas Gilbert 
3126c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3127c65b1445SDouglas Gilbert 		scsi_debug_virtual_gb = n;
312828898873SFUJITA Tomonori 
312928898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
313028898873SFUJITA Tomonori 
3131c65b1445SDouglas Gilbert 		return count;
3132c65b1445SDouglas Gilbert 	}
3133c65b1445SDouglas Gilbert 	return -EINVAL;
3134c65b1445SDouglas Gilbert }
3135c65b1445SDouglas Gilbert DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
3136c65b1445SDouglas Gilbert 	    sdebug_virtual_gb_store);
3137c65b1445SDouglas Gilbert 
31381da177e4SLinus Torvalds static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
31391da177e4SLinus Torvalds {
31401da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
31411da177e4SLinus Torvalds }
31421da177e4SLinus Torvalds 
31431da177e4SLinus Torvalds static ssize_t sdebug_add_host_store(struct device_driver * ddp,
31441da177e4SLinus Torvalds 				     const char * buf, size_t count)
31451da177e4SLinus Torvalds {
31461da177e4SLinus Torvalds 	int delta_hosts;
31471da177e4SLinus Torvalds 
3148f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
31491da177e4SLinus Torvalds 		return -EINVAL;
31501da177e4SLinus Torvalds 	if (delta_hosts > 0) {
31511da177e4SLinus Torvalds 		do {
31521da177e4SLinus Torvalds 			sdebug_add_adapter();
31531da177e4SLinus Torvalds 		} while (--delta_hosts);
31541da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
31551da177e4SLinus Torvalds 		do {
31561da177e4SLinus Torvalds 			sdebug_remove_adapter();
31571da177e4SLinus Torvalds 		} while (++delta_hosts);
31581da177e4SLinus Torvalds 	}
31591da177e4SLinus Torvalds 	return count;
31601da177e4SLinus Torvalds }
31611da177e4SLinus Torvalds DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
31621da177e4SLinus Torvalds 	    sdebug_add_host_store);
31631da177e4SLinus Torvalds 
316423183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
316523183910SDouglas Gilbert 					  char * buf)
316623183910SDouglas Gilbert {
316723183910SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
316823183910SDouglas Gilbert }
316923183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
317023183910SDouglas Gilbert 					   const char * buf, size_t count)
317123183910SDouglas Gilbert {
317223183910SDouglas Gilbert 	int n;
317323183910SDouglas Gilbert 
317423183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
317523183910SDouglas Gilbert 		scsi_debug_vpd_use_hostno = n;
317623183910SDouglas Gilbert 		return count;
317723183910SDouglas Gilbert 	}
317823183910SDouglas Gilbert 	return -EINVAL;
317923183910SDouglas Gilbert }
318023183910SDouglas Gilbert DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
318123183910SDouglas Gilbert 	    sdebug_vpd_use_hostno_store);
318223183910SDouglas Gilbert 
3183597136abSMartin K. Petersen static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf)
3184597136abSMartin K. Petersen {
3185597136abSMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
3186597136abSMartin K. Petersen }
3187597136abSMartin K. Petersen DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL);
3188597136abSMartin K. Petersen 
3189c6a44287SMartin K. Petersen static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf)
3190c6a44287SMartin K. Petersen {
3191c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
3192c6a44287SMartin K. Petersen }
3193c6a44287SMartin K. Petersen DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL);
3194c6a44287SMartin K. Petersen 
3195c6a44287SMartin K. Petersen static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf)
3196c6a44287SMartin K. Petersen {
3197c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
3198c6a44287SMartin K. Petersen }
3199c6a44287SMartin K. Petersen DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL);
3200c6a44287SMartin K. Petersen 
3201c6a44287SMartin K. Petersen static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf)
3202c6a44287SMartin K. Petersen {
3203c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard);
3204c6a44287SMartin K. Petersen }
3205c6a44287SMartin K. Petersen DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL);
3206c6a44287SMartin K. Petersen 
3207c6a44287SMartin K. Petersen static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf)
3208c6a44287SMartin K. Petersen {
3209c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
3210c6a44287SMartin K. Petersen }
3211c6a44287SMartin K. Petersen DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL);
3212c6a44287SMartin K. Petersen 
321344d92694SMartin K. Petersen static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf)
321444d92694SMartin K. Petersen {
321544d92694SMartin K. Petersen 	ssize_t count;
321644d92694SMartin K. Petersen 
32175b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
321844d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
321944d92694SMartin K. Petersen 				 sdebug_store_sectors);
322044d92694SMartin K. Petersen 
322144d92694SMartin K. Petersen 	count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
322244d92694SMartin K. Petersen 
322344d92694SMartin K. Petersen 	buf[count++] = '\n';
322444d92694SMartin K. Petersen 	buf[count++] = 0;
322544d92694SMartin K. Petersen 
322644d92694SMartin K. Petersen 	return count;
322744d92694SMartin K. Petersen }
322844d92694SMartin K. Petersen DRIVER_ATTR(map, S_IRUGO, sdebug_map_show, NULL);
322944d92694SMartin K. Petersen 
3230d986788bSMartin Pitt static ssize_t sdebug_removable_show(struct device_driver *ddp,
3231d986788bSMartin Pitt 				     char *buf)
3232d986788bSMartin Pitt {
3233d986788bSMartin Pitt 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_removable ? 1 : 0);
3234d986788bSMartin Pitt }
3235d986788bSMartin Pitt static ssize_t sdebug_removable_store(struct device_driver *ddp,
3236d986788bSMartin Pitt 				      const char *buf, size_t count)
3237d986788bSMartin Pitt {
3238d986788bSMartin Pitt 	int n;
3239d986788bSMartin Pitt 
3240d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3241d986788bSMartin Pitt 		scsi_debug_removable = (n > 0);
3242d986788bSMartin Pitt 		return count;
3243d986788bSMartin Pitt 	}
3244d986788bSMartin Pitt 	return -EINVAL;
3245d986788bSMartin Pitt }
3246d986788bSMartin Pitt DRIVER_ATTR(removable, S_IRUGO | S_IWUSR, sdebug_removable_show,
3247d986788bSMartin Pitt 	    sdebug_removable_store);
3248d986788bSMartin Pitt 
3249c6a44287SMartin K. Petersen 
325023183910SDouglas Gilbert /* Note: The following function creates attribute files in the
325123183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
325223183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
325323183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
325423183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
325523183910SDouglas Gilbert  */
32566ecaff7fSRandy Dunlap static int do_create_driverfs_files(void)
32571da177e4SLinus Torvalds {
32586ecaff7fSRandy Dunlap 	int ret;
32596ecaff7fSRandy Dunlap 
32606ecaff7fSRandy Dunlap 	ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
32616ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
32626ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
32636ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
32646ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
326523183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
32666ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
326778d4e5a0SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_queue);
326823183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
326978d4e5a0SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_uld);
32706ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
327123183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
32726ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
32736ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
3274d986788bSMartin Pitt 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_removable);
32756ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
327623183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
327723183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
3278597136abSMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
3279c6a44287SMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix);
3280c6a44287SMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif);
3281c6a44287SMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard);
3282c6a44287SMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato);
328344d92694SMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_map);
32846ecaff7fSRandy Dunlap 	return ret;
32851da177e4SLinus Torvalds }
32861da177e4SLinus Torvalds 
32871da177e4SLinus Torvalds static void do_remove_driverfs_files(void)
32881da177e4SLinus Torvalds {
328944d92694SMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_map);
3290c6a44287SMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato);
3291c6a44287SMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard);
3292c6a44287SMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif);
3293c6a44287SMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix);
3294597136abSMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
329523183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
329623183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
32971da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
32981da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
32991da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
3300d986788bSMartin Pitt 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_removable);
33011da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
330223183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
330378d4e5a0SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_uld);
330423183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
330578d4e5a0SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_queue);
33061da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
330723183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
33081da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
33091da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
33101da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
33111da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
33121da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
33131da177e4SLinus Torvalds }
33141da177e4SLinus Torvalds 
33159b906779SNicholas Bellinger struct device *pseudo_primary;
33168dea0d02SFUJITA Tomonori 
33171da177e4SLinus Torvalds static int __init scsi_debug_init(void)
33181da177e4SLinus Torvalds {
33195f2578e5SFUJITA Tomonori 	unsigned long sz;
33201da177e4SLinus Torvalds 	int host_to_add;
33211da177e4SLinus Torvalds 	int k;
33226ecaff7fSRandy Dunlap 	int ret;
33231da177e4SLinus Torvalds 
3324597136abSMartin K. Petersen 	switch (scsi_debug_sector_size) {
3325597136abSMartin K. Petersen 	case  512:
3326597136abSMartin K. Petersen 	case 1024:
3327597136abSMartin K. Petersen 	case 2048:
3328597136abSMartin K. Petersen 	case 4096:
3329597136abSMartin K. Petersen 		break;
3330597136abSMartin K. Petersen 	default:
3331c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n",
3332597136abSMartin K. Petersen 		       scsi_debug_sector_size);
3333597136abSMartin K. Petersen 		return -EINVAL;
3334597136abSMartin K. Petersen 	}
3335597136abSMartin K. Petersen 
3336c6a44287SMartin K. Petersen 	switch (scsi_debug_dif) {
3337c6a44287SMartin K. Petersen 
3338c6a44287SMartin K. Petersen 	case SD_DIF_TYPE0_PROTECTION:
3339c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
3340395cef03SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
3341c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
3342c6a44287SMartin K. Petersen 		break;
3343c6a44287SMartin K. Petersen 
3344c6a44287SMartin K. Petersen 	default:
3345395cef03SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n");
3346c6a44287SMartin K. Petersen 		return -EINVAL;
3347c6a44287SMartin K. Petersen 	}
3348c6a44287SMartin K. Petersen 
3349c6a44287SMartin K. Petersen 	if (scsi_debug_guard > 1) {
3350c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n");
3351c6a44287SMartin K. Petersen 		return -EINVAL;
3352c6a44287SMartin K. Petersen 	}
3353c6a44287SMartin K. Petersen 
3354c6a44287SMartin K. Petersen 	if (scsi_debug_ato > 1) {
3355c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n");
3356c6a44287SMartin K. Petersen 		return -EINVAL;
3357c6a44287SMartin K. Petersen 	}
3358c6a44287SMartin K. Petersen 
3359ea61fca5SMartin K. Petersen 	if (scsi_debug_physblk_exp > 15) {
3360ea61fca5SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n",
3361ea61fca5SMartin K. Petersen 		       scsi_debug_physblk_exp);
3362ea61fca5SMartin K. Petersen 		return -EINVAL;
3363ea61fca5SMartin K. Petersen 	}
3364ea61fca5SMartin K. Petersen 
3365ea61fca5SMartin K. Petersen 	if (scsi_debug_lowest_aligned > 0x3fff) {
3366ea61fca5SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n",
3367ea61fca5SMartin K. Petersen 		       scsi_debug_lowest_aligned);
3368ea61fca5SMartin K. Petersen 		return -EINVAL;
3369ea61fca5SMartin K. Petersen 	}
3370ea61fca5SMartin K. Petersen 
33711da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb < 1)
33721da177e4SLinus Torvalds 		scsi_debug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
33735f2578e5SFUJITA Tomonori 	sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
3374597136abSMartin K. Petersen 	sdebug_store_sectors = sz / scsi_debug_sector_size;
337528898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
33761da177e4SLinus Torvalds 
33771da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
33781da177e4SLinus Torvalds 	sdebug_heads = 8;
33791da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
33801da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb >= 16)
33811da177e4SLinus Torvalds 		sdebug_heads = 32;
33821da177e4SLinus Torvalds 	else if (scsi_debug_dev_size_mb >= 256)
33831da177e4SLinus Torvalds 		sdebug_heads = 64;
33841da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
33851da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
33861da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
33871da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
33881da177e4SLinus Torvalds 		sdebug_heads = 255;
33891da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
33901da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
33911da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
33921da177e4SLinus Torvalds 	}
33931da177e4SLinus Torvalds 
33941da177e4SLinus Torvalds 	fake_storep = vmalloc(sz);
33951da177e4SLinus Torvalds 	if (NULL == fake_storep) {
33961da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
33971da177e4SLinus Torvalds 		return -ENOMEM;
33981da177e4SLinus Torvalds 	}
33991da177e4SLinus Torvalds 	memset(fake_storep, 0, sz);
34001da177e4SLinus Torvalds 	if (scsi_debug_num_parts > 0)
3401f58b0efbSFUJITA Tomonori 		sdebug_build_parts(fake_storep, sz);
34021da177e4SLinus Torvalds 
3403c6a44287SMartin K. Petersen 	if (scsi_debug_dif) {
3404c6a44287SMartin K. Petersen 		int dif_size;
3405c6a44287SMartin K. Petersen 
3406c6a44287SMartin K. Petersen 		dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
3407c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
3408c6a44287SMartin K. Petersen 
3409c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n",
3410c6a44287SMartin K. Petersen 		       dif_size, dif_storep);
3411c6a44287SMartin K. Petersen 
3412c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
3413c6a44287SMartin K. Petersen 			printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n");
3414c6a44287SMartin K. Petersen 			ret = -ENOMEM;
3415c6a44287SMartin K. Petersen 			goto free_vm;
3416c6a44287SMartin K. Petersen 		}
3417c6a44287SMartin K. Petersen 
3418c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
3419c6a44287SMartin K. Petersen 	}
3420c6a44287SMartin K. Petersen 
34215b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
34225b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
34236014759cSMartin K. Petersen 		scsi_debug_unmap_max_blocks =
34246014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU);
34256014759cSMartin K. Petersen 
34266014759cSMartin K. Petersen 		scsi_debug_unmap_max_desc =
34276014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_max_desc, 0U, 256U);
34286014759cSMartin K. Petersen 
34296014759cSMartin K. Petersen 		scsi_debug_unmap_granularity =
34306014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU);
34316014759cSMartin K. Petersen 
34326014759cSMartin K. Petersen 		if (scsi_debug_unmap_alignment &&
3433ac17078aSAkinobu Mita 		    scsi_debug_unmap_granularity <=
3434ac17078aSAkinobu Mita 		    scsi_debug_unmap_alignment) {
343544d92694SMartin K. Petersen 			printk(KERN_ERR
3436ac17078aSAkinobu Mita 			       "%s: ERR: unmap_granularity <= unmap_alignment\n",
343744d92694SMartin K. Petersen 			       __func__);
343844d92694SMartin K. Petersen 			return -EINVAL;
343944d92694SMartin K. Petersen 		}
344044d92694SMartin K. Petersen 
3441b90ebc3dSAkinobu Mita 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
3442b90ebc3dSAkinobu Mita 		map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
344344d92694SMartin K. Petersen 
344444d92694SMartin K. Petersen 		printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n",
344544d92694SMartin K. Petersen 		       map_size);
344644d92694SMartin K. Petersen 
344744d92694SMartin K. Petersen 		if (map_storep == NULL) {
344844d92694SMartin K. Petersen 			printk(KERN_ERR "scsi_debug_init: out of mem. (MAP)\n");
344944d92694SMartin K. Petersen 			ret = -ENOMEM;
345044d92694SMartin K. Petersen 			goto free_vm;
345144d92694SMartin K. Petersen 		}
345244d92694SMartin K. Petersen 
3453b90ebc3dSAkinobu Mita 		bitmap_zero(map_storep, map_size);
345444d92694SMartin K. Petersen 
345544d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
345644d92694SMartin K. Petersen 		if (scsi_debug_num_parts)
345744d92694SMartin K. Petersen 			map_region(0, 2);
345844d92694SMartin K. Petersen 	}
345944d92694SMartin K. Petersen 
34609b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
34619b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
34629b906779SNicholas Bellinger 		printk(KERN_WARNING "scsi_debug: root_device_register() error\n");
34639b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
34646ecaff7fSRandy Dunlap 		goto free_vm;
34656ecaff7fSRandy Dunlap 	}
34666ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
34676ecaff7fSRandy Dunlap 	if (ret < 0) {
34686ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
34696ecaff7fSRandy Dunlap 			ret);
34706ecaff7fSRandy Dunlap 		goto dev_unreg;
34716ecaff7fSRandy Dunlap 	}
34726ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
34736ecaff7fSRandy Dunlap 	if (ret < 0) {
34746ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
34756ecaff7fSRandy Dunlap 			ret);
34766ecaff7fSRandy Dunlap 		goto bus_unreg;
34776ecaff7fSRandy Dunlap 	}
34786ecaff7fSRandy Dunlap 	ret = do_create_driverfs_files();
34796ecaff7fSRandy Dunlap 	if (ret < 0) {
34806ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
34816ecaff7fSRandy Dunlap 			ret);
34826ecaff7fSRandy Dunlap 		goto del_files;
34836ecaff7fSRandy Dunlap 	}
34841da177e4SLinus Torvalds 
34856ecaff7fSRandy Dunlap 	init_all_queued();
34861da177e4SLinus Torvalds 
34871da177e4SLinus Torvalds 	host_to_add = scsi_debug_add_host;
34881da177e4SLinus Torvalds         scsi_debug_add_host = 0;
34891da177e4SLinus Torvalds 
34901da177e4SLinus Torvalds         for (k = 0; k < host_to_add; k++) {
34911da177e4SLinus Torvalds                 if (sdebug_add_adapter()) {
34921da177e4SLinus Torvalds                         printk(KERN_ERR "scsi_debug_init: "
34931da177e4SLinus Torvalds                                "sdebug_add_adapter failed k=%d\n", k);
34941da177e4SLinus Torvalds                         break;
34951da177e4SLinus Torvalds                 }
34961da177e4SLinus Torvalds         }
34971da177e4SLinus Torvalds 
34981da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
34991da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
35001da177e4SLinus Torvalds 		       scsi_debug_add_host);
35011da177e4SLinus Torvalds 	}
35021da177e4SLinus Torvalds 	return 0;
35036ecaff7fSRandy Dunlap 
35046ecaff7fSRandy Dunlap del_files:
35056ecaff7fSRandy Dunlap 	do_remove_driverfs_files();
35066ecaff7fSRandy Dunlap 	driver_unregister(&sdebug_driverfs_driver);
35076ecaff7fSRandy Dunlap bus_unreg:
35086ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
35096ecaff7fSRandy Dunlap dev_unreg:
35109b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
35116ecaff7fSRandy Dunlap free_vm:
351244d92694SMartin K. Petersen 	if (map_storep)
351344d92694SMartin K. Petersen 		vfree(map_storep);
3514c6a44287SMartin K. Petersen 	if (dif_storep)
3515c6a44287SMartin K. Petersen 		vfree(dif_storep);
35166ecaff7fSRandy Dunlap 	vfree(fake_storep);
35176ecaff7fSRandy Dunlap 
35186ecaff7fSRandy Dunlap 	return ret;
35191da177e4SLinus Torvalds }
35201da177e4SLinus Torvalds 
35211da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
35221da177e4SLinus Torvalds {
35231da177e4SLinus Torvalds 	int k = scsi_debug_add_host;
35241da177e4SLinus Torvalds 
35251da177e4SLinus Torvalds 	stop_all_queued();
35261da177e4SLinus Torvalds 	for (; k; k--)
35271da177e4SLinus Torvalds 		sdebug_remove_adapter();
35281da177e4SLinus Torvalds 	do_remove_driverfs_files();
35291da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
35301da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
35319b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
35321da177e4SLinus Torvalds 
3533c6a44287SMartin K. Petersen 	if (dif_storep)
3534c6a44287SMartin K. Petersen 		vfree(dif_storep);
3535c6a44287SMartin K. Petersen 
35361da177e4SLinus Torvalds 	vfree(fake_storep);
35371da177e4SLinus Torvalds }
35381da177e4SLinus Torvalds 
35391da177e4SLinus Torvalds device_initcall(scsi_debug_init);
35401da177e4SLinus Torvalds module_exit(scsi_debug_exit);
35411da177e4SLinus Torvalds 
35421da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev)
35431da177e4SLinus Torvalds {
35441da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
35451da177e4SLinus Torvalds 
35461da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
35471da177e4SLinus Torvalds         kfree(sdbg_host);
35481da177e4SLinus Torvalds }
35491da177e4SLinus Torvalds 
35501da177e4SLinus Torvalds static int sdebug_add_adapter(void)
35511da177e4SLinus Torvalds {
35521da177e4SLinus Torvalds 	int k, devs_per_host;
35531da177e4SLinus Torvalds         int error = 0;
35541da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
35558b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
35561da177e4SLinus Torvalds 
355724669f75SJes Sorensen         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
35581da177e4SLinus Torvalds         if (NULL == sdbg_host) {
35591da177e4SLinus Torvalds                 printk(KERN_ERR "%s: out of memory at line %d\n",
3560cadbd4a5SHarvey Harrison                        __func__, __LINE__);
35611da177e4SLinus Torvalds                 return -ENOMEM;
35621da177e4SLinus Torvalds         }
35631da177e4SLinus Torvalds 
35641da177e4SLinus Torvalds         INIT_LIST_HEAD(&sdbg_host->dev_info_list);
35651da177e4SLinus Torvalds 
35661da177e4SLinus Torvalds 	devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
35671da177e4SLinus Torvalds         for (k = 0; k < devs_per_host; k++) {
35685cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
35695cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
35701da177e4SLinus Torvalds                         printk(KERN_ERR "%s: out of memory at line %d\n",
3571cadbd4a5SHarvey Harrison                                __func__, __LINE__);
35721da177e4SLinus Torvalds                         error = -ENOMEM;
35731da177e4SLinus Torvalds 			goto clean;
35741da177e4SLinus Torvalds                 }
35751da177e4SLinus Torvalds         }
35761da177e4SLinus Torvalds 
35771da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
35781da177e4SLinus Torvalds         list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
35791da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
35801da177e4SLinus Torvalds 
35811da177e4SLinus Torvalds         sdbg_host->dev.bus = &pseudo_lld_bus;
35829b906779SNicholas Bellinger         sdbg_host->dev.parent = pseudo_primary;
35831da177e4SLinus Torvalds         sdbg_host->dev.release = &sdebug_release_adapter;
358471610f55SKay Sievers         dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
35851da177e4SLinus Torvalds 
35861da177e4SLinus Torvalds         error = device_register(&sdbg_host->dev);
35871da177e4SLinus Torvalds 
35881da177e4SLinus Torvalds         if (error)
35891da177e4SLinus Torvalds 		goto clean;
35901da177e4SLinus Torvalds 
35911da177e4SLinus Torvalds 	++scsi_debug_add_host;
35921da177e4SLinus Torvalds         return error;
35931da177e4SLinus Torvalds 
35941da177e4SLinus Torvalds clean:
35958b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
35968b40228fSFUJITA Tomonori 				 dev_list) {
35971da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
35981da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
35991da177e4SLinus Torvalds 	}
36001da177e4SLinus Torvalds 
36011da177e4SLinus Torvalds 	kfree(sdbg_host);
36021da177e4SLinus Torvalds         return error;
36031da177e4SLinus Torvalds }
36041da177e4SLinus Torvalds 
36051da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
36061da177e4SLinus Torvalds {
36071da177e4SLinus Torvalds         struct sdebug_host_info * sdbg_host = NULL;
36081da177e4SLinus Torvalds 
36091da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
36101da177e4SLinus Torvalds         if (!list_empty(&sdebug_host_list)) {
36111da177e4SLinus Torvalds                 sdbg_host = list_entry(sdebug_host_list.prev,
36121da177e4SLinus Torvalds                                        struct sdebug_host_info, host_list);
36131da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
36141da177e4SLinus Torvalds 	}
36151da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
36161da177e4SLinus Torvalds 
36171da177e4SLinus Torvalds 	if (!sdbg_host)
36181da177e4SLinus Torvalds 		return;
36191da177e4SLinus Torvalds 
36201da177e4SLinus Torvalds         device_unregister(&sdbg_host->dev);
36211da177e4SLinus Torvalds         --scsi_debug_add_host;
36221da177e4SLinus Torvalds }
36231da177e4SLinus Torvalds 
3624639db475SFUJITA Tomonori static
3625f281233dSJeff Garzik int scsi_debug_queuecommand_lck(struct scsi_cmnd *SCpnt, done_funct_t done)
3626639db475SFUJITA Tomonori {
3627639db475SFUJITA Tomonori 	unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
3628639db475SFUJITA Tomonori 	int len, k;
3629639db475SFUJITA Tomonori 	unsigned int num;
3630639db475SFUJITA Tomonori 	unsigned long long lba;
3631395cef03SMartin K. Petersen 	u32 ei_lba;
3632639db475SFUJITA Tomonori 	int errsts = 0;
3633639db475SFUJITA Tomonori 	int target = SCpnt->device->id;
3634639db475SFUJITA Tomonori 	struct sdebug_dev_info *devip = NULL;
3635639db475SFUJITA Tomonori 	int inj_recovered = 0;
3636639db475SFUJITA Tomonori 	int inj_transport = 0;
3637c6a44287SMartin K. Petersen 	int inj_dif = 0;
3638c6a44287SMartin K. Petersen 	int inj_dix = 0;
3639639db475SFUJITA Tomonori 	int delay_override = 0;
364044d92694SMartin K. Petersen 	int unmap = 0;
3641639db475SFUJITA Tomonori 
3642639db475SFUJITA Tomonori 	scsi_set_resid(SCpnt, 0);
3643639db475SFUJITA Tomonori 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
3644639db475SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: cmd ");
3645639db475SFUJITA Tomonori 		for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
3646639db475SFUJITA Tomonori 			printk("%02x ", (int)cmd[k]);
3647639db475SFUJITA Tomonori 		printk("\n");
3648639db475SFUJITA Tomonori 	}
3649639db475SFUJITA Tomonori 
3650639db475SFUJITA Tomonori 	if (target == SCpnt->device->host->hostt->this_id) {
3651639db475SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: initiator's id used as "
3652639db475SFUJITA Tomonori 		       "target!\n");
3653639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
3654639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
3655639db475SFUJITA Tomonori 	}
3656639db475SFUJITA Tomonori 
3657639db475SFUJITA Tomonori 	if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
3658639db475SFUJITA Tomonori 	    (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
3659639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
3660639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
3661639db475SFUJITA Tomonori 	devip = devInfoReg(SCpnt->device);
3662639db475SFUJITA Tomonori 	if (NULL == devip)
3663639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
3664639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
3665639db475SFUJITA Tomonori 
3666639db475SFUJITA Tomonori 	if ((scsi_debug_every_nth != 0) &&
3667639db475SFUJITA Tomonori 	    (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
3668639db475SFUJITA Tomonori 		scsi_debug_cmnd_count = 0;
3669639db475SFUJITA Tomonori 		if (scsi_debug_every_nth < -1)
3670639db475SFUJITA Tomonori 			scsi_debug_every_nth = -1;
3671639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
3672639db475SFUJITA Tomonori 			return 0; /* ignore command causing timeout */
367318a4d0a2SMartin K. Petersen 		else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts &&
367418a4d0a2SMartin K. Petersen 			 scsi_medium_access_command(SCpnt))
367518a4d0a2SMartin K. Petersen 			return 0; /* time out reads and writes */
3676639db475SFUJITA Tomonori 		else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
3677639db475SFUJITA Tomonori 			inj_recovered = 1; /* to reads and writes below */
3678639db475SFUJITA Tomonori 		else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
3679639db475SFUJITA Tomonori 			inj_transport = 1; /* to reads and writes below */
3680c6a44287SMartin K. Petersen 		else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
3681c6a44287SMartin K. Petersen 			inj_dif = 1; /* to reads and writes below */
3682c6a44287SMartin K. Petersen 		else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
3683c6a44287SMartin K. Petersen 			inj_dix = 1; /* to reads and writes below */
3684639db475SFUJITA Tomonori 	}
3685639db475SFUJITA Tomonori 
3686639db475SFUJITA Tomonori 	if (devip->wlun) {
3687639db475SFUJITA Tomonori 		switch (*cmd) {
3688639db475SFUJITA Tomonori 		case INQUIRY:
3689639db475SFUJITA Tomonori 		case REQUEST_SENSE:
3690639db475SFUJITA Tomonori 		case TEST_UNIT_READY:
3691639db475SFUJITA Tomonori 		case REPORT_LUNS:
3692639db475SFUJITA Tomonori 			break;  /* only allowable wlun commands */
3693639db475SFUJITA Tomonori 		default:
3694639db475SFUJITA Tomonori 			if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3695639db475SFUJITA Tomonori 				printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
3696639db475SFUJITA Tomonori 				       "not supported for wlun\n", *cmd);
3697639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3698639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
3699639db475SFUJITA Tomonori 			errsts = check_condition_result;
3700639db475SFUJITA Tomonori 			return schedule_resp(SCpnt, devip, done, errsts,
3701639db475SFUJITA Tomonori 					     0);
3702639db475SFUJITA Tomonori 		}
3703639db475SFUJITA Tomonori 	}
3704639db475SFUJITA Tomonori 
3705639db475SFUJITA Tomonori 	switch (*cmd) {
3706639db475SFUJITA Tomonori 	case INQUIRY:     /* mandatory, ignore unit attention */
3707639db475SFUJITA Tomonori 		delay_override = 1;
3708639db475SFUJITA Tomonori 		errsts = resp_inquiry(SCpnt, target, devip);
3709639db475SFUJITA Tomonori 		break;
3710639db475SFUJITA Tomonori 	case REQUEST_SENSE:	/* mandatory, ignore unit attention */
3711639db475SFUJITA Tomonori 		delay_override = 1;
3712639db475SFUJITA Tomonori 		errsts = resp_requests(SCpnt, devip);
3713639db475SFUJITA Tomonori 		break;
3714639db475SFUJITA Tomonori 	case REZERO_UNIT:	/* actually this is REWIND for SSC */
3715639db475SFUJITA Tomonori 	case START_STOP:
3716639db475SFUJITA Tomonori 		errsts = resp_start_stop(SCpnt, devip);
3717639db475SFUJITA Tomonori 		break;
3718639db475SFUJITA Tomonori 	case ALLOW_MEDIUM_REMOVAL:
3719639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3720639db475SFUJITA Tomonori 		if (errsts)
3721639db475SFUJITA Tomonori 			break;
3722639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3723639db475SFUJITA Tomonori 			printk(KERN_INFO "scsi_debug: Medium removal %s\n",
3724639db475SFUJITA Tomonori 			       cmd[4] ? "inhibited" : "enabled");
3725639db475SFUJITA Tomonori 		break;
3726639db475SFUJITA Tomonori 	case SEND_DIAGNOSTIC:     /* mandatory */
3727639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3728639db475SFUJITA Tomonori 		break;
3729639db475SFUJITA Tomonori 	case TEST_UNIT_READY:     /* mandatory */
3730639db475SFUJITA Tomonori 		delay_override = 1;
3731639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3732639db475SFUJITA Tomonori 		break;
3733639db475SFUJITA Tomonori 	case RESERVE:
3734639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3735639db475SFUJITA Tomonori 		break;
3736639db475SFUJITA Tomonori 	case RESERVE_10:
3737639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3738639db475SFUJITA Tomonori 		break;
3739639db475SFUJITA Tomonori 	case RELEASE:
3740639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3741639db475SFUJITA Tomonori 		break;
3742639db475SFUJITA Tomonori 	case RELEASE_10:
3743639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3744639db475SFUJITA Tomonori 		break;
3745639db475SFUJITA Tomonori 	case READ_CAPACITY:
3746639db475SFUJITA Tomonori 		errsts = resp_readcap(SCpnt, devip);
3747639db475SFUJITA Tomonori 		break;
3748639db475SFUJITA Tomonori 	case SERVICE_ACTION_IN:
374944d92694SMartin K. Petersen 		if (cmd[1] == SAI_READ_CAPACITY_16)
375044d92694SMartin K. Petersen 			errsts = resp_readcap16(SCpnt, devip);
375144d92694SMartin K. Petersen 		else if (cmd[1] == SAI_GET_LBA_STATUS) {
375244d92694SMartin K. Petersen 
37535b94e232SMartin K. Petersen 			if (scsi_debug_lbp() == 0) {
375444d92694SMartin K. Petersen 				mk_sense_buffer(devip, ILLEGAL_REQUEST,
375544d92694SMartin K. Petersen 						INVALID_COMMAND_OPCODE, 0);
375644d92694SMartin K. Petersen 				errsts = check_condition_result;
375744d92694SMartin K. Petersen 			} else
375844d92694SMartin K. Petersen 				errsts = resp_get_lba_status(SCpnt, devip);
375944d92694SMartin K. Petersen 		} else {
3760639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3761639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
3762639db475SFUJITA Tomonori 			errsts = check_condition_result;
3763639db475SFUJITA Tomonori 		}
3764639db475SFUJITA Tomonori 		break;
3765639db475SFUJITA Tomonori 	case MAINTENANCE_IN:
3766639db475SFUJITA Tomonori 		if (MI_REPORT_TARGET_PGS != cmd[1]) {
3767639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3768639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
3769639db475SFUJITA Tomonori 			errsts = check_condition_result;
3770639db475SFUJITA Tomonori 			break;
3771639db475SFUJITA Tomonori 		}
3772639db475SFUJITA Tomonori 		errsts = resp_report_tgtpgs(SCpnt, devip);
3773639db475SFUJITA Tomonori 		break;
3774639db475SFUJITA Tomonori 	case READ_16:
3775639db475SFUJITA Tomonori 	case READ_12:
3776639db475SFUJITA Tomonori 	case READ_10:
3777395cef03SMartin K. Petersen 		/* READ{10,12,16} and DIF Type 2 are natural enemies */
3778395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3779395cef03SMartin K. Petersen 		    cmd[1] & 0xe0) {
3780395cef03SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3781395cef03SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
3782395cef03SMartin K. Petersen 			errsts = check_condition_result;
3783395cef03SMartin K. Petersen 			break;
3784395cef03SMartin K. Petersen 		}
3785395cef03SMartin K. Petersen 
3786395cef03SMartin K. Petersen 		if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3787395cef03SMartin K. Petersen 		     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3788395cef03SMartin K. Petersen 		    (cmd[1] & 0xe0) == 0)
3789395cef03SMartin K. Petersen 			printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3790395cef03SMartin K. Petersen 
3791395cef03SMartin K. Petersen 		/* fall through */
3792639db475SFUJITA Tomonori 	case READ_6:
3793395cef03SMartin K. Petersen read:
3794639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3795639db475SFUJITA Tomonori 		if (errsts)
3796639db475SFUJITA Tomonori 			break;
3797639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
3798639db475SFUJITA Tomonori 			break;
3799395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3800395cef03SMartin K. Petersen 		errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
3801639db475SFUJITA Tomonori 		if (inj_recovered && (0 == errsts)) {
3802639db475SFUJITA Tomonori 			mk_sense_buffer(devip, RECOVERED_ERROR,
3803639db475SFUJITA Tomonori 					THRESHOLD_EXCEEDED, 0);
3804639db475SFUJITA Tomonori 			errsts = check_condition_result;
3805639db475SFUJITA Tomonori 		} else if (inj_transport && (0 == errsts)) {
3806639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ABORTED_COMMAND,
3807639db475SFUJITA Tomonori 					TRANSPORT_PROBLEM, ACK_NAK_TO);
3808639db475SFUJITA Tomonori 			errsts = check_condition_result;
3809c6a44287SMartin K. Petersen 		} else if (inj_dif && (0 == errsts)) {
3810c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3811c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3812c6a44287SMartin K. Petersen 		} else if (inj_dix && (0 == errsts)) {
3813c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3814c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3815639db475SFUJITA Tomonori 		}
3816639db475SFUJITA Tomonori 		break;
3817639db475SFUJITA Tomonori 	case REPORT_LUNS:	/* mandatory, ignore unit attention */
3818639db475SFUJITA Tomonori 		delay_override = 1;
3819639db475SFUJITA Tomonori 		errsts = resp_report_luns(SCpnt, devip);
3820639db475SFUJITA Tomonori 		break;
3821639db475SFUJITA Tomonori 	case VERIFY:		/* 10 byte SBC-2 command */
3822639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3823639db475SFUJITA Tomonori 		break;
3824639db475SFUJITA Tomonori 	case WRITE_16:
3825639db475SFUJITA Tomonori 	case WRITE_12:
3826639db475SFUJITA Tomonori 	case WRITE_10:
3827395cef03SMartin K. Petersen 		/* WRITE{10,12,16} and DIF Type 2 are natural enemies */
3828395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3829395cef03SMartin K. Petersen 		    cmd[1] & 0xe0) {
3830395cef03SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3831395cef03SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
3832395cef03SMartin K. Petersen 			errsts = check_condition_result;
3833395cef03SMartin K. Petersen 			break;
3834395cef03SMartin K. Petersen 		}
3835395cef03SMartin K. Petersen 
3836395cef03SMartin K. Petersen 		if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3837395cef03SMartin K. Petersen 		     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3838395cef03SMartin K. Petersen 		    (cmd[1] & 0xe0) == 0)
3839395cef03SMartin K. Petersen 			printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3840395cef03SMartin K. Petersen 
3841395cef03SMartin K. Petersen 		/* fall through */
3842639db475SFUJITA Tomonori 	case WRITE_6:
3843395cef03SMartin K. Petersen write:
3844639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3845639db475SFUJITA Tomonori 		if (errsts)
3846639db475SFUJITA Tomonori 			break;
3847639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
3848639db475SFUJITA Tomonori 			break;
3849395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3850395cef03SMartin K. Petersen 		errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
3851639db475SFUJITA Tomonori 		if (inj_recovered && (0 == errsts)) {
3852639db475SFUJITA Tomonori 			mk_sense_buffer(devip, RECOVERED_ERROR,
3853639db475SFUJITA Tomonori 					THRESHOLD_EXCEEDED, 0);
3854639db475SFUJITA Tomonori 			errsts = check_condition_result;
3855c6a44287SMartin K. Petersen 		} else if (inj_dif && (0 == errsts)) {
3856c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3857c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3858c6a44287SMartin K. Petersen 		} else if (inj_dix && (0 == errsts)) {
3859c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3860c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3861639db475SFUJITA Tomonori 		}
3862639db475SFUJITA Tomonori 		break;
386344d92694SMartin K. Petersen 	case WRITE_SAME_16:
38645b94e232SMartin K. Petersen 	case WRITE_SAME:
38656014759cSMartin K. Petersen 		if (cmd[1] & 0x8) {
38665b94e232SMartin K. Petersen 			if ((*cmd == WRITE_SAME_16 && scsi_debug_lbpws == 0) ||
38675b94e232SMartin K. Petersen 			    (*cmd == WRITE_SAME && scsi_debug_lbpws10 == 0)) {
38686014759cSMartin K. Petersen 				mk_sense_buffer(devip, ILLEGAL_REQUEST,
38696014759cSMartin K. Petersen 						INVALID_FIELD_IN_CDB, 0);
38706014759cSMartin K. Petersen 				errsts = check_condition_result;
38716014759cSMartin K. Petersen 			} else
387244d92694SMartin K. Petersen 				unmap = 1;
38736014759cSMartin K. Petersen 		}
38746014759cSMartin K. Petersen 		if (errsts)
38756014759cSMartin K. Petersen 			break;
387644d92694SMartin K. Petersen 		errsts = check_readiness(SCpnt, 0, devip);
387744d92694SMartin K. Petersen 		if (errsts)
387844d92694SMartin K. Petersen 			break;
387944d92694SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
388044d92694SMartin K. Petersen 		errsts = resp_write_same(SCpnt, lba, num, devip, ei_lba, unmap);
388144d92694SMartin K. Petersen 		break;
388244d92694SMartin K. Petersen 	case UNMAP:
388344d92694SMartin K. Petersen 		errsts = check_readiness(SCpnt, 0, devip);
388444d92694SMartin K. Petersen 		if (errsts)
388544d92694SMartin K. Petersen 			break;
388644d92694SMartin K. Petersen 
38875b94e232SMartin K. Petersen 		if (scsi_debug_unmap_max_desc == 0 || scsi_debug_lbpu == 0) {
388844d92694SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
388944d92694SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
389044d92694SMartin K. Petersen 			errsts = check_condition_result;
389144d92694SMartin K. Petersen 		} else
389244d92694SMartin K. Petersen 			errsts = resp_unmap(SCpnt, devip);
389344d92694SMartin K. Petersen 		break;
3894639db475SFUJITA Tomonori 	case MODE_SENSE:
3895639db475SFUJITA Tomonori 	case MODE_SENSE_10:
3896639db475SFUJITA Tomonori 		errsts = resp_mode_sense(SCpnt, target, devip);
3897639db475SFUJITA Tomonori 		break;
3898639db475SFUJITA Tomonori 	case MODE_SELECT:
3899639db475SFUJITA Tomonori 		errsts = resp_mode_select(SCpnt, 1, devip);
3900639db475SFUJITA Tomonori 		break;
3901639db475SFUJITA Tomonori 	case MODE_SELECT_10:
3902639db475SFUJITA Tomonori 		errsts = resp_mode_select(SCpnt, 0, devip);
3903639db475SFUJITA Tomonori 		break;
3904639db475SFUJITA Tomonori 	case LOG_SENSE:
3905639db475SFUJITA Tomonori 		errsts = resp_log_sense(SCpnt, devip);
3906639db475SFUJITA Tomonori 		break;
3907639db475SFUJITA Tomonori 	case SYNCHRONIZE_CACHE:
3908639db475SFUJITA Tomonori 		delay_override = 1;
3909639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3910639db475SFUJITA Tomonori 		break;
3911639db475SFUJITA Tomonori 	case WRITE_BUFFER:
3912639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3913639db475SFUJITA Tomonori 		break;
3914639db475SFUJITA Tomonori 	case XDWRITEREAD_10:
3915639db475SFUJITA Tomonori 		if (!scsi_bidi_cmnd(SCpnt)) {
3916639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3917639db475SFUJITA Tomonori 					INVALID_FIELD_IN_CDB, 0);
3918639db475SFUJITA Tomonori 			errsts = check_condition_result;
3919639db475SFUJITA Tomonori 			break;
3920639db475SFUJITA Tomonori 		}
3921639db475SFUJITA Tomonori 
3922639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3923639db475SFUJITA Tomonori 		if (errsts)
3924639db475SFUJITA Tomonori 			break;
3925639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
3926639db475SFUJITA Tomonori 			break;
3927395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3928395cef03SMartin K. Petersen 		errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
3929639db475SFUJITA Tomonori 		if (errsts)
3930639db475SFUJITA Tomonori 			break;
3931395cef03SMartin K. Petersen 		errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
3932639db475SFUJITA Tomonori 		if (errsts)
3933639db475SFUJITA Tomonori 			break;
3934639db475SFUJITA Tomonori 		errsts = resp_xdwriteread(SCpnt, lba, num, devip);
3935639db475SFUJITA Tomonori 		break;
3936395cef03SMartin K. Petersen 	case VARIABLE_LENGTH_CMD:
3937395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
3938395cef03SMartin K. Petersen 
3939395cef03SMartin K. Petersen 			if ((cmd[10] & 0xe0) == 0)
3940395cef03SMartin K. Petersen 				printk(KERN_ERR
3941395cef03SMartin K. Petersen 				       "Unprotected RD/WR to DIF device\n");
3942395cef03SMartin K. Petersen 
3943395cef03SMartin K. Petersen 			if (cmd[9] == READ_32) {
3944395cef03SMartin K. Petersen 				BUG_ON(SCpnt->cmd_len < 32);
3945395cef03SMartin K. Petersen 				goto read;
3946395cef03SMartin K. Petersen 			}
3947395cef03SMartin K. Petersen 
3948395cef03SMartin K. Petersen 			if (cmd[9] == WRITE_32) {
3949395cef03SMartin K. Petersen 				BUG_ON(SCpnt->cmd_len < 32);
3950395cef03SMartin K. Petersen 				goto write;
3951395cef03SMartin K. Petersen 			}
3952395cef03SMartin K. Petersen 		}
3953395cef03SMartin K. Petersen 
3954395cef03SMartin K. Petersen 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
3955395cef03SMartin K. Petersen 				INVALID_FIELD_IN_CDB, 0);
3956395cef03SMartin K. Petersen 		errsts = check_condition_result;
3957395cef03SMartin K. Petersen 		break;
3958395cef03SMartin K. Petersen 
3959639db475SFUJITA Tomonori 	default:
3960639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3961639db475SFUJITA Tomonori 			printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
3962639db475SFUJITA Tomonori 			       "supported\n", *cmd);
3963639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3964639db475SFUJITA Tomonori 		if (errsts)
3965639db475SFUJITA Tomonori 			break;	/* Unit attention takes precedence */
3966639db475SFUJITA Tomonori 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
3967639db475SFUJITA Tomonori 		errsts = check_condition_result;
3968639db475SFUJITA Tomonori 		break;
3969639db475SFUJITA Tomonori 	}
3970639db475SFUJITA Tomonori 	return schedule_resp(SCpnt, devip, done, errsts,
3971639db475SFUJITA Tomonori 			     (delay_override ? 0 : scsi_debug_delay));
3972639db475SFUJITA Tomonori }
3973639db475SFUJITA Tomonori 
3974f281233dSJeff Garzik static DEF_SCSI_QCMD(scsi_debug_queuecommand)
3975f281233dSJeff Garzik 
39769e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
3977c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
3978c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
39799e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
39809e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
39819e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
39829e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
39839e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
39849e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
39859e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
39869e603ca0SFUJITA Tomonori 	.queuecommand =		scsi_debug_queuecommand,
39879e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
39889e603ca0SFUJITA Tomonori 	.eh_bus_reset_handler = scsi_debug_bus_reset,
39899e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
39909e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
39919e603ca0SFUJITA Tomonori 	.bios_param =		scsi_debug_biosparam,
39929e603ca0SFUJITA Tomonori 	.can_queue =		SCSI_DEBUG_CANQUEUE,
39939e603ca0SFUJITA Tomonori 	.this_id =		7,
39949e603ca0SFUJITA Tomonori 	.sg_tablesize =		256,
39959e603ca0SFUJITA Tomonori 	.cmd_per_lun =		16,
39969e603ca0SFUJITA Tomonori 	.max_sectors =		0xffff,
39979e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
39989e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
39999e603ca0SFUJITA Tomonori };
40009e603ca0SFUJITA Tomonori 
40011da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev)
40021da177e4SLinus Torvalds {
40031da177e4SLinus Torvalds         int error = 0;
40041da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
40051da177e4SLinus Torvalds         struct Scsi_Host *hpnt;
4006c6a44287SMartin K. Petersen 	int host_prot;
40071da177e4SLinus Torvalds 
40081da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
40091da177e4SLinus Torvalds 
401078d4e5a0SDouglas Gilbert 	sdebug_driver_template.can_queue = scsi_debug_max_queue;
40111da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
40121da177e4SLinus Torvalds 	if (NULL == hpnt) {
4013cadbd4a5SHarvey Harrison 		printk(KERN_ERR "%s: scsi_register failed\n", __func__);
40141da177e4SLinus Torvalds 		error = -ENODEV;
40151da177e4SLinus Torvalds 		return error;
40161da177e4SLinus Torvalds 	}
40171da177e4SLinus Torvalds 
40181da177e4SLinus Torvalds         sdbg_host->shost = hpnt;
40191da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
40201da177e4SLinus Torvalds 	if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
40211da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts + 1;
40221da177e4SLinus Torvalds 	else
40231da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts;
4024c65b1445SDouglas Gilbert 	hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;	/* = scsi_debug_max_luns; */
40251da177e4SLinus Torvalds 
4026c6a44287SMartin K. Petersen 	host_prot = 0;
4027c6a44287SMartin K. Petersen 
4028c6a44287SMartin K. Petersen 	switch (scsi_debug_dif) {
4029c6a44287SMartin K. Petersen 
4030c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
4031c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE1_PROTECTION;
4032c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
4033c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE1_PROTECTION;
4034c6a44287SMartin K. Petersen 		break;
4035c6a44287SMartin K. Petersen 
4036c6a44287SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
4037c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE2_PROTECTION;
4038c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
4039c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE2_PROTECTION;
4040c6a44287SMartin K. Petersen 		break;
4041c6a44287SMartin K. Petersen 
4042c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
4043c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE3_PROTECTION;
4044c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
4045c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE3_PROTECTION;
4046c6a44287SMartin K. Petersen 		break;
4047c6a44287SMartin K. Petersen 
4048c6a44287SMartin K. Petersen 	default:
4049c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
4050c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE0_PROTECTION;
4051c6a44287SMartin K. Petersen 		break;
4052c6a44287SMartin K. Petersen 	}
4053c6a44287SMartin K. Petersen 
4054c6a44287SMartin K. Petersen 	scsi_host_set_prot(hpnt, host_prot);
4055c6a44287SMartin K. Petersen 
4056c6a44287SMartin K. Petersen 	printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
4057c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
4058c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
4059c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
4060c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
4061c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
4062c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
4063c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
4064c6a44287SMartin K. Petersen 
4065c6a44287SMartin K. Petersen 	if (scsi_debug_guard == 1)
4066c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
4067c6a44287SMartin K. Petersen 	else
4068c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
4069c6a44287SMartin K. Petersen 
40701da177e4SLinus Torvalds         error = scsi_add_host(hpnt, &sdbg_host->dev);
40711da177e4SLinus Torvalds         if (error) {
4072cadbd4a5SHarvey Harrison                 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
40731da177e4SLinus Torvalds                 error = -ENODEV;
40741da177e4SLinus Torvalds 		scsi_host_put(hpnt);
40751da177e4SLinus Torvalds         } else
40761da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
40771da177e4SLinus Torvalds 
40781da177e4SLinus Torvalds 
40791da177e4SLinus Torvalds         return error;
40801da177e4SLinus Torvalds }
40811da177e4SLinus Torvalds 
40821da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev)
40831da177e4SLinus Torvalds {
40841da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
40858b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
40861da177e4SLinus Torvalds 
40871da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
40881da177e4SLinus Torvalds 
40891da177e4SLinus Torvalds 	if (!sdbg_host) {
40901da177e4SLinus Torvalds 		printk(KERN_ERR "%s: Unable to locate host info\n",
4091cadbd4a5SHarvey Harrison 		       __func__);
40921da177e4SLinus Torvalds 		return -ENODEV;
40931da177e4SLinus Torvalds 	}
40941da177e4SLinus Torvalds 
40951da177e4SLinus Torvalds         scsi_remove_host(sdbg_host->shost);
40961da177e4SLinus Torvalds 
40978b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
40988b40228fSFUJITA Tomonori 				 dev_list) {
40991da177e4SLinus Torvalds                 list_del(&sdbg_devinfo->dev_list);
41001da177e4SLinus Torvalds                 kfree(sdbg_devinfo);
41011da177e4SLinus Torvalds         }
41021da177e4SLinus Torvalds 
41031da177e4SLinus Torvalds         scsi_host_put(sdbg_host->shost);
41041da177e4SLinus Torvalds         return 0;
41051da177e4SLinus Torvalds }
41061da177e4SLinus Torvalds 
41078dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
41088dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
41091da177e4SLinus Torvalds {
41108dea0d02SFUJITA Tomonori 	return 1;
41118dea0d02SFUJITA Tomonori }
41121da177e4SLinus Torvalds 
41138dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
41148dea0d02SFUJITA Tomonori 	.name = "pseudo",
41158dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
41168dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
41178dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
41188dea0d02SFUJITA Tomonori };
4119