xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 6bb5e6e7)
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
67c5af0db9SAkinobu Mita #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
681da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
69c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
701da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
711da177e4SLinus Torvalds #define ADDR_OUT_OF_RANGE 0x21
72395cef03SMartin K. Petersen #define INVALID_COMMAND_OPCODE 0x20
731da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
74c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
751da177e4SLinus Torvalds #define POWERON_RESET 0x29
761da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
776f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
78c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
79c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
801da177e4SLinus Torvalds 
816f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
826f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
836f3cbf55SDouglas Gilbert 
841da177e4SLinus Torvalds #define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds /* Default values for driver parameters */
871da177e4SLinus Torvalds #define DEF_NUM_HOST   1
881da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
891da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
901da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
911da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
921da177e4SLinus Torvalds  */
935b94e232SMartin K. Petersen #define DEF_ATO 1
941da177e4SLinus Torvalds #define DEF_DELAY   1
951da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
965b94e232SMartin K. Petersen #define DEF_DIF 0
975b94e232SMartin K. Petersen #define DEF_DIX 0
985b94e232SMartin K. Petersen #define DEF_D_SENSE   0
991da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1005b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1015b94e232SMartin K. Petersen #define DEF_GUARD 0
1025b94e232SMartin K. Petersen #define DEF_LBPU 0
1035b94e232SMartin K. Petersen #define DEF_LBPWS 0
1045b94e232SMartin K. Petersen #define DEF_LBPWS10 0
105be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1065b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
1075b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1081da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1091da177e4SLinus Torvalds #define DEF_OPTS   0
110e308b3d1SMartin K. Petersen #define DEF_OPT_BLKS 64
1115b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
1125b94e232SMartin K. Petersen #define DEF_PTYPE   0
113d986788bSMartin Pitt #define DEF_REMOVABLE false
1145b94e232SMartin K. Petersen #define DEF_SCSI_LEVEL   5    /* INQUIRY, byte2 [5->SPC-3] */
1155b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1165b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1175b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1186014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1196014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1205b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1215b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1225b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
1231da177e4SLinus Torvalds 
1241da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */
1251da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE   1
1261da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR   2
1271da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT   4
1281da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR   8
1296f3cbf55SDouglas Gilbert #define SCSI_DEBUG_OPT_TRANSPORT_ERR   16
130c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIF_ERR   32
131c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIX_ERR   64
13218a4d0a2SMartin K. Petersen #define SCSI_DEBUG_OPT_MAC_TIMEOUT  128
133b57d7c01SChristoph Hellwig #define SCSI_DEBUG_OPT_SHORT_TRANSFER	256
1341da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
1351da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1361da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1371da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1386f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1396f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1401da177e4SLinus Torvalds  *
1411da177e4SLinus Torvalds  * When "every_nth" < 0 then after "- every_nth" commands:
1421da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1431da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1441da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1456f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1466f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1471da177e4SLinus Torvalds  * This will continue until some other action occurs (e.g. the user
1481da177e4SLinus Torvalds  * writing a new value (other than -1 or 1) to every_nth via sysfs).
1491da177e4SLinus Torvalds  */
1501da177e4SLinus Torvalds 
1511da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
1521da177e4SLinus Torvalds  * sector on read commands: */
1531da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
15432f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
1571da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
1581da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
159c65b1445SDouglas Gilbert #define SAM2_WLUN_REPORT_LUNS 0xc101
1601da177e4SLinus Torvalds 
16178d4e5a0SDouglas Gilbert /* Can queue up to this number of commands. Typically commands that
16278d4e5a0SDouglas Gilbert  * that have a non-zero delay are queued. */
16378d4e5a0SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE  255
16478d4e5a0SDouglas Gilbert 
1651da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST;
1665b94e232SMartin K. Petersen static int scsi_debug_ato = DEF_ATO;
1671da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY;
1681da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
1695b94e232SMartin K. Petersen static int scsi_debug_dif = DEF_DIF;
1705b94e232SMartin K. Petersen static int scsi_debug_dix = DEF_DIX;
1715b94e232SMartin K. Petersen static int scsi_debug_dsense = DEF_D_SENSE;
1721da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH;
1735b94e232SMartin K. Petersen static int scsi_debug_fake_rw = DEF_FAKE_RW;
17468aee7baSAkinobu Mita static unsigned int scsi_debug_guard = DEF_GUARD;
1755b94e232SMartin K. Petersen static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
1761da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS;
17778d4e5a0SDouglas Gilbert static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE;
178c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
1795b94e232SMartin K. Petersen static int scsi_debug_no_uld = 0;
1805b94e232SMartin K. Petersen static int scsi_debug_num_parts = DEF_NUM_PARTS;
1815b94e232SMartin K. Petersen static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
182e308b3d1SMartin K. Petersen static int scsi_debug_opt_blks = DEF_OPT_BLKS;
1835b94e232SMartin K. Petersen static int scsi_debug_opts = DEF_OPTS;
1845b94e232SMartin K. Petersen static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
1855b94e232SMartin K. Petersen static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
1865b94e232SMartin K. Petersen static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
1875b94e232SMartin K. Petersen static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
1885b94e232SMartin K. Petersen static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
1895b94e232SMartin K. Petersen static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
1905b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpu = DEF_LBPU;
1915b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws = DEF_LBPWS;
1925b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10;
193be1dd78dSEric Sandeen static unsigned int scsi_debug_lbprz = DEF_LBPRZ;
1946014759cSMartin K. Petersen static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
1955b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
1965b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
1975b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
1985b94e232SMartin K. Petersen static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH;
199d986788bSMartin Pitt static bool scsi_debug_removable = DEF_REMOVABLE;
2000759c666SAkinobu Mita static bool scsi_debug_clustering;
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds static int scsi_debug_cmnd_count = 0;
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds #define DEV_READONLY(TGT)      (0)
2051da177e4SLinus Torvalds 
206c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
2071da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
2101da177e4SLinus Torvalds    may still need them */
2111da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
2121da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
2131da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
2141da177e4SLinus Torvalds 
2151da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4
2161da177e4SLinus Torvalds 
2171da177e4SLinus Torvalds #define SDEBUG_SENSE_LEN 32
2181da177e4SLinus Torvalds 
219395cef03SMartin K. Petersen #define SCSI_DEBUG_MAX_CMD_LEN 32
2209e603ca0SFUJITA Tomonori 
2215b94e232SMartin K. Petersen static unsigned int scsi_debug_lbp(void)
2225b94e232SMartin K. Petersen {
2235b94e232SMartin K. Petersen 	return scsi_debug_lbpu | scsi_debug_lbpws | scsi_debug_lbpws10;
2245b94e232SMartin K. Petersen }
2255b94e232SMartin K. Petersen 
2261da177e4SLinus Torvalds struct sdebug_dev_info {
2271da177e4SLinus Torvalds 	struct list_head dev_list;
2281da177e4SLinus Torvalds 	unsigned char sense_buff[SDEBUG_SENSE_LEN];	/* weak nexus */
2291da177e4SLinus Torvalds 	unsigned int channel;
2301da177e4SLinus Torvalds 	unsigned int target;
2311da177e4SLinus Torvalds 	unsigned int lun;
2321da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
233c65b1445SDouglas Gilbert 	unsigned int wlun;
2341da177e4SLinus Torvalds 	char reset;
235c65b1445SDouglas Gilbert 	char stopped;
2361da177e4SLinus Torvalds 	char used;
2371da177e4SLinus Torvalds };
2381da177e4SLinus Torvalds 
2391da177e4SLinus Torvalds struct sdebug_host_info {
2401da177e4SLinus Torvalds 	struct list_head host_list;
2411da177e4SLinus Torvalds 	struct Scsi_Host *shost;
2421da177e4SLinus Torvalds 	struct device dev;
2431da177e4SLinus Torvalds 	struct list_head dev_info_list;
2441da177e4SLinus Torvalds };
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds #define to_sdebug_host(d)	\
2471da177e4SLinus Torvalds 	container_of(d, struct sdebug_host_info, dev)
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
2501da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds typedef void (* done_funct_t) (struct scsi_cmnd *);
2531da177e4SLinus Torvalds 
2541da177e4SLinus Torvalds struct sdebug_queued_cmd {
2551da177e4SLinus Torvalds 	int in_use;
2561da177e4SLinus Torvalds 	struct timer_list cmnd_timer;
2571da177e4SLinus Torvalds 	done_funct_t done_funct;
2581da177e4SLinus Torvalds 	struct scsi_cmnd * a_cmnd;
2591da177e4SLinus Torvalds 	int scsi_result;
2601da177e4SLinus Torvalds };
2611da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
2621da177e4SLinus Torvalds 
2631da177e4SLinus Torvalds static unsigned char * fake_storep;	/* ramdisk storage */
264e18d8beaSAkinobu Mita static struct sd_dif_tuple *dif_storep;	/* protection info */
26544d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
2661da177e4SLinus Torvalds 
26744d92694SMartin K. Petersen static unsigned long map_size;
2681da177e4SLinus Torvalds static int num_aborts = 0;
2691da177e4SLinus Torvalds static int num_dev_resets = 0;
2701da177e4SLinus Torvalds static int num_bus_resets = 0;
2711da177e4SLinus Torvalds static int num_host_resets = 0;
272c6a44287SMartin K. Petersen static int dix_writes;
273c6a44287SMartin K. Petersen static int dix_reads;
274c6a44287SMartin K. Petersen static int dif_errors;
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock);
2771da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
2781da177e4SLinus Torvalds 
2791da177e4SLinus Torvalds static char sdebug_proc_name[] = "scsi_debug";
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
2841da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
2851da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
2861da177e4SLinus Torvalds };
2871da177e4SLinus Torvalds 
2881da177e4SLinus Torvalds static const int check_condition_result =
2891da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
2901da177e4SLinus Torvalds 
291c6a44287SMartin K. Petersen static const int illegal_condition_result =
292c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
293c6a44287SMartin K. Petersen 
294c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
295c65b1445SDouglas Gilbert 				    0, 0, 0x2, 0x4b};
296c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
297c65b1445SDouglas Gilbert 			           0, 0, 0x0, 0x0};
298c65b1445SDouglas Gilbert 
29914faa944SAkinobu Mita static void *fake_store(unsigned long long lba)
30014faa944SAkinobu Mita {
30114faa944SAkinobu Mita 	lba = do_div(lba, sdebug_store_sectors);
30214faa944SAkinobu Mita 
30314faa944SAkinobu Mita 	return fake_storep + lba * scsi_debug_sector_size;
30414faa944SAkinobu Mita }
30514faa944SAkinobu Mita 
30614faa944SAkinobu Mita static struct sd_dif_tuple *dif_store(sector_t sector)
30714faa944SAkinobu Mita {
30814faa944SAkinobu Mita 	sector = do_div(sector, sdebug_store_sectors);
30914faa944SAkinobu Mita 
31014faa944SAkinobu Mita 	return dif_storep + sector;
31114faa944SAkinobu Mita }
31214faa944SAkinobu Mita 
3131da177e4SLinus Torvalds static int sdebug_add_adapter(void);
3141da177e4SLinus Torvalds static void sdebug_remove_adapter(void);
3151da177e4SLinus Torvalds 
3168dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
3178dea0d02SFUJITA Tomonori {
3188dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
3198dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
3208dea0d02SFUJITA Tomonori 
3218dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
3228dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3238dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
3248dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
3258dea0d02SFUJITA Tomonori 		    (scsi_debug_num_tgts > hpnt->this_id))
3268dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts + 1;
3278dea0d02SFUJITA Tomonori 		else
3288dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts;
3298dea0d02SFUJITA Tomonori 		/* scsi_debug_max_luns; */
3308dea0d02SFUJITA Tomonori 		hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
3318dea0d02SFUJITA Tomonori 	}
3328dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
3338dea0d02SFUJITA Tomonori }
3348dea0d02SFUJITA Tomonori 
3358dea0d02SFUJITA Tomonori static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
3368dea0d02SFUJITA Tomonori 			    int asc, int asq)
3378dea0d02SFUJITA Tomonori {
3388dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
3398dea0d02SFUJITA Tomonori 
3408dea0d02SFUJITA Tomonori 	sbuff = devip->sense_buff;
3418dea0d02SFUJITA Tomonori 	memset(sbuff, 0, SDEBUG_SENSE_LEN);
3428dea0d02SFUJITA Tomonori 
3438dea0d02SFUJITA Tomonori 	scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
3448dea0d02SFUJITA Tomonori 
3458dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3468dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug:    [sense_key,asc,ascq]: "
3478dea0d02SFUJITA Tomonori 		      "[0x%x,0x%x,0x%x]\n", key, asc, asq);
3488dea0d02SFUJITA Tomonori }
3491da177e4SLinus Torvalds 
3503de9f944SFUJITA Tomonori static void get_data_transfer_info(unsigned char *cmd,
351395cef03SMartin K. Petersen 				   unsigned long long *lba, unsigned int *num,
352395cef03SMartin K. Petersen 				   u32 *ei_lba)
3533de9f944SFUJITA Tomonori {
354395cef03SMartin K. Petersen 	*ei_lba = 0;
355395cef03SMartin K. Petersen 
3563de9f944SFUJITA Tomonori 	switch (*cmd) {
357395cef03SMartin K. Petersen 	case VARIABLE_LENGTH_CMD:
358395cef03SMartin K. Petersen 		*lba = (u64)cmd[19] | (u64)cmd[18] << 8 |
359395cef03SMartin K. Petersen 			(u64)cmd[17] << 16 | (u64)cmd[16] << 24 |
360395cef03SMartin K. Petersen 			(u64)cmd[15] << 32 | (u64)cmd[14] << 40 |
361395cef03SMartin K. Petersen 			(u64)cmd[13] << 48 | (u64)cmd[12] << 56;
362395cef03SMartin K. Petersen 
363395cef03SMartin K. Petersen 		*ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 |
364395cef03SMartin K. Petersen 			(u32)cmd[21] << 16 | (u32)cmd[20] << 24;
365395cef03SMartin K. Petersen 
366395cef03SMartin K. Petersen 		*num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 |
367395cef03SMartin K. Petersen 			(u32)cmd[28] << 24;
368395cef03SMartin K. Petersen 		break;
369395cef03SMartin K. Petersen 
37044d92694SMartin K. Petersen 	case WRITE_SAME_16:
3713de9f944SFUJITA Tomonori 	case WRITE_16:
3723de9f944SFUJITA Tomonori 	case READ_16:
373d5cdc989SFUJITA Tomonori 		*lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
374d5cdc989SFUJITA Tomonori 			(u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
375d5cdc989SFUJITA Tomonori 			(u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
376d5cdc989SFUJITA Tomonori 			(u64)cmd[3] << 48 | (u64)cmd[2] << 56;
377d5cdc989SFUJITA Tomonori 
378d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
379d5cdc989SFUJITA Tomonori 			(u32)cmd[10] << 24;
3803de9f944SFUJITA Tomonori 		break;
3813de9f944SFUJITA Tomonori 	case WRITE_12:
3823de9f944SFUJITA Tomonori 	case READ_12:
383d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
384d5cdc989SFUJITA Tomonori 			(u32)cmd[2] << 24;
385d5cdc989SFUJITA Tomonori 
386d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
387d5cdc989SFUJITA Tomonori 			(u32)cmd[6] << 24;
3883de9f944SFUJITA Tomonori 		break;
38944d92694SMartin K. Petersen 	case WRITE_SAME:
3903de9f944SFUJITA Tomonori 	case WRITE_10:
3913de9f944SFUJITA Tomonori 	case READ_10:
392c639d14eSFUJITA Tomonori 	case XDWRITEREAD_10:
393d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[5] | (u32)cmd[4] << 8 |	(u32)cmd[3] << 16 |
394d5cdc989SFUJITA Tomonori 			(u32)cmd[2] << 24;
395d5cdc989SFUJITA Tomonori 
396d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[8] | (u32)cmd[7] << 8;
3973de9f944SFUJITA Tomonori 		break;
3983de9f944SFUJITA Tomonori 	case WRITE_6:
3993de9f944SFUJITA Tomonori 	case READ_6:
400d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
401d5cdc989SFUJITA Tomonori 			(u32)(cmd[1] & 0x1f) << 16;
4023de9f944SFUJITA Tomonori 		*num = (0 == cmd[4]) ? 256 : cmd[4];
4033de9f944SFUJITA Tomonori 		break;
4043de9f944SFUJITA Tomonori 	default:
4053de9f944SFUJITA Tomonori 		break;
4063de9f944SFUJITA Tomonori 	}
4073de9f944SFUJITA Tomonori }
4081da177e4SLinus Torvalds 
4091da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
4101da177e4SLinus Torvalds {
4111da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
4121da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
4131da177e4SLinus Torvalds 	}
4141da177e4SLinus Torvalds 	return -EINVAL;
4151da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
4161da177e4SLinus Torvalds }
4171da177e4SLinus Torvalds 
418c65b1445SDouglas Gilbert static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
419c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
4201da177e4SLinus Torvalds {
4211da177e4SLinus Torvalds 	if (devip->reset) {
4221da177e4SLinus Torvalds 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
4231da177e4SLinus Torvalds 			printk(KERN_INFO "scsi_debug: Reporting Unit "
4241da177e4SLinus Torvalds 			       "attention: power on reset\n");
4251da177e4SLinus Torvalds 		devip->reset = 0;
4261da177e4SLinus Torvalds 		mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
4271da177e4SLinus Torvalds 		return check_condition_result;
4281da177e4SLinus Torvalds 	}
429c65b1445SDouglas Gilbert 	if ((0 == reset_only) && devip->stopped) {
430c65b1445SDouglas Gilbert 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
431c65b1445SDouglas Gilbert 			printk(KERN_INFO "scsi_debug: Reporting Not "
432c65b1445SDouglas Gilbert 			       "ready: initializing command required\n");
433c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
434c65b1445SDouglas Gilbert 				0x2);
435c65b1445SDouglas Gilbert 		return check_condition_result;
436c65b1445SDouglas Gilbert 	}
4371da177e4SLinus Torvalds 	return 0;
4381da177e4SLinus Torvalds }
4391da177e4SLinus Torvalds 
4401da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
4411da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
4421da177e4SLinus Torvalds 				int arr_len)
4431da177e4SLinus Torvalds {
44421a61829SFUJITA Tomonori 	int act_len;
445072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
4461da177e4SLinus Torvalds 
447072d0bb3SFUJITA Tomonori 	if (!sdb->length)
4481da177e4SLinus Torvalds 		return 0;
449072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
4501da177e4SLinus Torvalds 		return (DID_ERROR << 16);
45121a61829SFUJITA Tomonori 
45221a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
45321a61829SFUJITA Tomonori 				      arr, arr_len);
45421a61829SFUJITA Tomonori 	sdb->resid = scsi_bufflen(scp) - act_len;
45521a61829SFUJITA Tomonori 
4561da177e4SLinus Torvalds 	return 0;
4571da177e4SLinus Torvalds }
4581da177e4SLinus Torvalds 
4591da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */
4601da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
46121a61829SFUJITA Tomonori 			       int arr_len)
4621da177e4SLinus Torvalds {
46321a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
4641da177e4SLinus Torvalds 		return 0;
465072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
4661da177e4SLinus Torvalds 		return -1;
46721a61829SFUJITA Tomonori 
46821a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
4691da177e4SLinus Torvalds }
4701da177e4SLinus Torvalds 
4711da177e4SLinus Torvalds 
4721da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux   ";
4731da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug      ";
4741da177e4SLinus Torvalds static const char * inq_product_rev = "0004";
4751da177e4SLinus Torvalds 
4765a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
4775a09e398SHannes Reinecke 			   int target_dev_id, int dev_id_num,
4785a09e398SHannes Reinecke 			   const char * dev_id_str,
479c65b1445SDouglas Gilbert 			   int dev_id_str_len)
4801da177e4SLinus Torvalds {
481c65b1445SDouglas Gilbert 	int num, port_a;
482c65b1445SDouglas Gilbert 	char b[32];
4831da177e4SLinus Torvalds 
484c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
4851da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
4861da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
4871da177e4SLinus Torvalds 	arr[1] = 0x1;
4881da177e4SLinus Torvalds 	arr[2] = 0x0;
4891da177e4SLinus Torvalds 	memcpy(&arr[4], inq_vendor_id, 8);
4901da177e4SLinus Torvalds 	memcpy(&arr[12], inq_product_id, 16);
4911da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
4921da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
4931da177e4SLinus Torvalds 	arr[3] = num;
4941da177e4SLinus Torvalds 	num += 4;
495c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
496c65b1445SDouglas Gilbert 		/* NAA-5, Logical unit identifier (binary) */
497c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* binary (not necessarily sas) */
498c65b1445SDouglas Gilbert 		arr[num++] = 0x3;	/* PIV=0, lu, naa */
499c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
500c65b1445SDouglas Gilbert 		arr[num++] = 0x8;
501c65b1445SDouglas Gilbert 		arr[num++] = 0x53;  /* naa-5 ieee company id=0x333333 (fake) */
502c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
503c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
504c65b1445SDouglas Gilbert 		arr[num++] = 0x30;
505c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 24);
506c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 16) & 0xff;
507c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 8) & 0xff;
508c65b1445SDouglas Gilbert 		arr[num++] = dev_id_num & 0xff;
509c65b1445SDouglas Gilbert 		/* Target relative port number */
510c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
511c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
512c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
513c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
514c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
515c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
516c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
517c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
518c65b1445SDouglas Gilbert 	}
519c65b1445SDouglas Gilbert 	/* NAA-5, Target port identifier */
520c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
521c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
522c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
523c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
524c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
525c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
526c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
527c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
528c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
529c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
530c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
531c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
5325a09e398SHannes Reinecke 	/* NAA-5, Target port group identifier */
5335a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
5345a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
5355a09e398SHannes Reinecke 	arr[num++] = 0x0;
5365a09e398SHannes Reinecke 	arr[num++] = 0x4;
5375a09e398SHannes Reinecke 	arr[num++] = 0;
5385a09e398SHannes Reinecke 	arr[num++] = 0;
5395a09e398SHannes Reinecke 	arr[num++] = (port_group_id >> 8) & 0xff;
5405a09e398SHannes Reinecke 	arr[num++] = port_group_id & 0xff;
541c65b1445SDouglas Gilbert 	/* NAA-5, Target device identifier */
542c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
543c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
544c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
545c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
546c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
547c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
548c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
549c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
550c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 24);
551c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 16) & 0xff;
552c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 8) & 0xff;
553c65b1445SDouglas Gilbert 	arr[num++] = target_dev_id & 0xff;
554c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
555c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
556c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
557c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
558c65b1445SDouglas Gilbert 	arr[num++] = 24;
559c65b1445SDouglas Gilbert 	memcpy(arr + num, "naa.52222220", 12);
560c65b1445SDouglas Gilbert 	num += 12;
561c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
562c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
563c65b1445SDouglas Gilbert 	num += 8;
564c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
565c65b1445SDouglas Gilbert 	num += 4;
566c65b1445SDouglas Gilbert 	return num;
567c65b1445SDouglas Gilbert }
568c65b1445SDouglas Gilbert 
569c65b1445SDouglas Gilbert 
570c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
571c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
572c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
573c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
574c65b1445SDouglas Gilbert };
575c65b1445SDouglas Gilbert 
576c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr)
577c65b1445SDouglas Gilbert {
578c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
579c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
580c65b1445SDouglas Gilbert }
581c65b1445SDouglas Gilbert 
582c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr)
583c65b1445SDouglas Gilbert {
584c65b1445SDouglas Gilbert 	int num = 0;
585c65b1445SDouglas Gilbert 	const char * na1 = "https://www.kernel.org/config";
586c65b1445SDouglas Gilbert 	const char * na2 = "http://www.kernel.org/log";
587c65b1445SDouglas Gilbert 	int plen, olen;
588c65b1445SDouglas Gilbert 
589c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
590c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
591c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
592c65b1445SDouglas Gilbert 	olen = strlen(na1);
593c65b1445SDouglas Gilbert 	plen = olen + 1;
594c65b1445SDouglas Gilbert 	if (plen % 4)
595c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
596c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
597c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
598c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
599c65b1445SDouglas Gilbert 	num += plen;
600c65b1445SDouglas Gilbert 
601c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
602c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
603c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
604c65b1445SDouglas Gilbert 	olen = strlen(na2);
605c65b1445SDouglas Gilbert 	plen = olen + 1;
606c65b1445SDouglas Gilbert 	if (plen % 4)
607c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
608c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
609c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
610c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
611c65b1445SDouglas Gilbert 	num += plen;
612c65b1445SDouglas Gilbert 
613c65b1445SDouglas Gilbert 	return num;
614c65b1445SDouglas Gilbert }
615c65b1445SDouglas Gilbert 
616c65b1445SDouglas Gilbert /* SCSI ports VPD page */
617c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
618c65b1445SDouglas Gilbert {
619c65b1445SDouglas Gilbert 	int num = 0;
620c65b1445SDouglas Gilbert 	int port_a, port_b;
621c65b1445SDouglas Gilbert 
622c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
623c65b1445SDouglas Gilbert 	port_b = port_a + 1;
624c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
625c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
626c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
627c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
628c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
629c65b1445SDouglas Gilbert 	num += 6;
630c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
631c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
632c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
633c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
634c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
635c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
636c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
637c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
638c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
639c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
640c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
641c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
642c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
643c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
644c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
645c65b1445SDouglas Gilbert 
646c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
647c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
648c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
649c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
650c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
651c65b1445SDouglas Gilbert 	num += 6;
652c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
653c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
654c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
655c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
656c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
657c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
658c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
659c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
660c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
661c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
662c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
663c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 24);
664c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 16) & 0xff;
665c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 8) & 0xff;
666c65b1445SDouglas Gilbert 	arr[num++] = port_b & 0xff;
667c65b1445SDouglas Gilbert 
668c65b1445SDouglas Gilbert 	return num;
669c65b1445SDouglas Gilbert }
670c65b1445SDouglas Gilbert 
671c65b1445SDouglas Gilbert 
672c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
673c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
674c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
675c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
676c65b1445SDouglas Gilbert '1','2','3','4',
677c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
678c65b1445SDouglas Gilbert 0xec,0,0,0,
679c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
680c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
681c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
682c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
683c65b1445SDouglas Gilbert 0x53,0x41,
684c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
685c65b1445SDouglas Gilbert 0x20,0x20,
686c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
687c65b1445SDouglas Gilbert 0x10,0x80,
688c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
689c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
690c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
691c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
692c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
693c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
694c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,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 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
699c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
700c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
701c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
702c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
703c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
704c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
705c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
706c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
707c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
708c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
709c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
710c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
711c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
712c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
713c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
714c65b1445SDouglas Gilbert };
715c65b1445SDouglas Gilbert 
716c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr)
717c65b1445SDouglas Gilbert {
718c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
719c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
720c65b1445SDouglas Gilbert }
721c65b1445SDouglas Gilbert 
722c65b1445SDouglas Gilbert 
7231e49f785SDouglas Gilbert /* Block limits VPD page (SBC-3) */
724c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
7251e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
7261e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7271e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7281e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
729c65b1445SDouglas Gilbert };
730c65b1445SDouglas Gilbert 
731c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr)
732c65b1445SDouglas Gilbert {
733ea61fca5SMartin K. Petersen 	unsigned int gran;
734ea61fca5SMartin K. Petersen 
735c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
736e308b3d1SMartin K. Petersen 
737e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
738ea61fca5SMartin K. Petersen 	gran = 1 << scsi_debug_physblk_exp;
739ea61fca5SMartin K. Petersen 	arr[2] = (gran >> 8) & 0xff;
740ea61fca5SMartin K. Petersen 	arr[3] = gran & 0xff;
741e308b3d1SMartin K. Petersen 
742e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
743c65b1445SDouglas Gilbert 	if (sdebug_store_sectors > 0x400) {
744c65b1445SDouglas Gilbert 		arr[4] = (sdebug_store_sectors >> 24) & 0xff;
745c65b1445SDouglas Gilbert 		arr[5] = (sdebug_store_sectors >> 16) & 0xff;
746c65b1445SDouglas Gilbert 		arr[6] = (sdebug_store_sectors >> 8) & 0xff;
747c65b1445SDouglas Gilbert 		arr[7] = sdebug_store_sectors & 0xff;
748c65b1445SDouglas Gilbert 	}
74944d92694SMartin K. Petersen 
750e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
751e308b3d1SMartin K. Petersen 	put_unaligned_be32(scsi_debug_opt_blks, &arr[8]);
752e308b3d1SMartin K. Petersen 
7535b94e232SMartin K. Petersen 	if (scsi_debug_lbpu) {
754e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
7556014759cSMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]);
756e308b3d1SMartin K. Petersen 
757e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
75844d92694SMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
75944d92694SMartin K. Petersen 	}
76044d92694SMartin K. Petersen 
761e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
76244d92694SMartin K. Petersen 	if (scsi_debug_unmap_alignment) {
76344d92694SMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
76444d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
76544d92694SMartin K. Petersen 	}
76644d92694SMartin K. Petersen 
767e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
76844d92694SMartin K. Petersen 	put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
7696014759cSMartin K. Petersen 
7705b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
7715b94e232SMartin K. Petersen 	put_unaligned_be64(scsi_debug_write_same_length, &arr[32]);
7725b94e232SMartin K. Petersen 
7735b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
77444d92694SMartin K. Petersen 
775c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
7761da177e4SLinus Torvalds }
7771da177e4SLinus Torvalds 
7781e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
779eac6e8e4SMatthew Wilcox static int inquiry_evpd_b1(unsigned char *arr)
780eac6e8e4SMatthew Wilcox {
781eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
782eac6e8e4SMatthew Wilcox 	arr[0] = 0;
7831e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
7841e49f785SDouglas Gilbert 	arr[2] = 0;
7851e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
786eac6e8e4SMatthew Wilcox 
787eac6e8e4SMatthew Wilcox 	return 0x3c;
788eac6e8e4SMatthew Wilcox }
7891da177e4SLinus Torvalds 
790be1dd78dSEric Sandeen /* Logical block provisioning VPD page (SBC-3) */
7916014759cSMartin K. Petersen static int inquiry_evpd_b2(unsigned char *arr)
7926014759cSMartin K. Petersen {
7933f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
7946014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
7956014759cSMartin K. Petersen 
7965b94e232SMartin K. Petersen 	if (scsi_debug_lbpu)
7976014759cSMartin K. Petersen 		arr[1] = 1 << 7;
7986014759cSMartin K. Petersen 
7995b94e232SMartin K. Petersen 	if (scsi_debug_lbpws)
8006014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
8016014759cSMartin K. Petersen 
8025b94e232SMartin K. Petersen 	if (scsi_debug_lbpws10)
8035b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
8045b94e232SMartin K. Petersen 
805be1dd78dSEric Sandeen 	if (scsi_debug_lbprz)
806be1dd78dSEric Sandeen 		arr[1] |= 1 << 2;
807be1dd78dSEric Sandeen 
8083f0bc3b3SMartin K. Petersen 	return 0x4;
8096014759cSMartin K. Petersen }
8106014759cSMartin K. Petersen 
8111da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
812c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
8131da177e4SLinus Torvalds 
8141da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd * scp, int target,
8151da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
8161da177e4SLinus Torvalds {
8171da177e4SLinus Torvalds 	unsigned char pq_pdt;
8185a09e398SHannes Reinecke 	unsigned char * arr;
8191da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
8205a09e398SHannes Reinecke 	int alloc_len, n, ret;
8211da177e4SLinus Torvalds 
8221da177e4SLinus Torvalds 	alloc_len = (cmd[3] << 8) + cmd[4];
8236f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
8246f3cbf55SDouglas Gilbert 	if (! arr)
8256f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
826c65b1445SDouglas Gilbert 	if (devip->wlun)
827c65b1445SDouglas Gilbert 		pq_pdt = 0x1e;	/* present, wlun */
828c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (0 == devip->lun))
829c65b1445SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, no device type */
830c65b1445SDouglas Gilbert 	else
8311da177e4SLinus Torvalds 		pq_pdt = (scsi_debug_ptype & 0x1f);
8321da177e4SLinus Torvalds 	arr[0] = pq_pdt;
8331da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
8341da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
8351da177e4SLinus Torvalds 			       	0);
8365a09e398SHannes Reinecke 		kfree(arr);
8371da177e4SLinus Torvalds 		return check_condition_result;
8381da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
8395a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
840c65b1445SDouglas Gilbert 		char lu_id_str[6];
841c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
8421da177e4SLinus Torvalds 
8435a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
8445a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
84523183910SDouglas Gilbert 		if (0 == scsi_debug_vpd_use_hostno)
84623183910SDouglas Gilbert 			host_no = 0;
847c65b1445SDouglas Gilbert 		lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
848c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
849c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
850c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
851c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
8521da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
853c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
854c65b1445SDouglas Gilbert 			n = 4;
855c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
856c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
857c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
858c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
859c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
860c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
861c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
862c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
863c65b1445SDouglas Gilbert 			arr[n++] = 0x89;  /* ATA information */
864c65b1445SDouglas Gilbert 			arr[n++] = 0xb0;  /* Block limits (SBC) */
865eac6e8e4SMatthew Wilcox 			arr[n++] = 0xb1;  /* Block characteristics (SBC) */
8665b94e232SMartin K. Petersen 			if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
8675b94e232SMartin K. Petersen 				arr[n++] = 0xb2;
868c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
8691da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
870c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
8711da177e4SLinus Torvalds 			arr[3] = len;
872c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
8731da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
874c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
8755a09e398SHannes Reinecke 			arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
8765a09e398SHannes Reinecke 						 target_dev_id, lu_id_num,
8775a09e398SHannes Reinecke 						 lu_id_str, len);
878c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
879c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
880c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_84(&arr[4]);
881c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
882c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
883c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_85(&arr[4]);
884c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
885c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
886c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
887c6a44287SMartin K. Petersen 			if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
888c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
889c6a44287SMartin K. Petersen 			else if (scsi_debug_dif)
890c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
891c6a44287SMartin K. Petersen 			else
892c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
893c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
894c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
895c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
896c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
897c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
898c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
899c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
900c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
901c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
902c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
903c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
904c65b1445SDouglas Gilbert 		} else if (0x89 == cmd[2]) { /* ATA information */
905c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
906c65b1445SDouglas Gilbert 			n = inquiry_evpd_89(&arr[4]);
907c65b1445SDouglas Gilbert 			arr[2] = (n >> 8);
908c65b1445SDouglas Gilbert 			arr[3] = (n & 0xff);
909c65b1445SDouglas Gilbert 		} else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
910c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
911c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_b0(&arr[4]);
912eac6e8e4SMatthew Wilcox 		} else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
913eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
914eac6e8e4SMatthew Wilcox 			arr[3] = inquiry_evpd_b1(&arr[4]);
9155b94e232SMartin K. Petersen 		} else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
9166014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
9176014759cSMartin K. Petersen 			arr[3] = inquiry_evpd_b2(&arr[4]);
9181da177e4SLinus Torvalds 		} else {
9191da177e4SLinus Torvalds 			/* Illegal request, invalid field in cdb */
9201da177e4SLinus Torvalds 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
9211da177e4SLinus Torvalds 					INVALID_FIELD_IN_CDB, 0);
9225a09e398SHannes Reinecke 			kfree(arr);
9231da177e4SLinus Torvalds 			return check_condition_result;
9241da177e4SLinus Torvalds 		}
925c65b1445SDouglas Gilbert 		len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
9265a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
927c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
9285a09e398SHannes Reinecke 		kfree(arr);
9295a09e398SHannes Reinecke 		return ret;
9301da177e4SLinus Torvalds 	}
9311da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
932d986788bSMartin Pitt 	arr[1] = scsi_debug_removable ? 0x80 : 0;	/* Removable disk */
9331da177e4SLinus Torvalds 	arr[2] = scsi_debug_scsi_level;
9341da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
9351da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
936c6a44287SMartin K. Petersen 	arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
9375a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno)
9385a09e398SHannes Reinecke 		arr[5] = 0x10; /* claim: implicit TGPS */
939c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
9401da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
941c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
9421da177e4SLinus Torvalds 	memcpy(&arr[8], inq_vendor_id, 8);
9431da177e4SLinus Torvalds 	memcpy(&arr[16], inq_product_id, 16);
9441da177e4SLinus Torvalds 	memcpy(&arr[32], inq_product_rev, 4);
9451da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
946c65b1445SDouglas Gilbert 	arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
947c65b1445SDouglas Gilbert 	arr[60] = 0x3; arr[61] = 0x14;  /* SPC-3 ANSI */
948c65b1445SDouglas Gilbert 	n = 62;
9491da177e4SLinus Torvalds 	if (scsi_debug_ptype == 0) {
950c65b1445SDouglas Gilbert 		arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
9511da177e4SLinus Torvalds 	} else if (scsi_debug_ptype == 1) {
952c65b1445SDouglas Gilbert 		arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
9531da177e4SLinus Torvalds 	}
954c65b1445SDouglas Gilbert 	arr[n++] = 0xc; arr[n++] = 0xf;  /* SAS-1.1 rev 10 */
9555a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
9561da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
9575a09e398SHannes Reinecke 	kfree(arr);
9585a09e398SHannes Reinecke 	return ret;
9591da177e4SLinus Torvalds }
9601da177e4SLinus Torvalds 
9611da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp,
9621da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip)
9631da177e4SLinus Torvalds {
9641da177e4SLinus Torvalds 	unsigned char * sbuff;
9651da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
9661da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_SENSE_LEN];
967c65b1445SDouglas Gilbert 	int want_dsense;
9681da177e4SLinus Torvalds 	int len = 18;
9691da177e4SLinus Torvalds 
970c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
9711da177e4SLinus Torvalds 	if (devip->reset == 1)
972c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
973c65b1445SDouglas Gilbert 	want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
9741da177e4SLinus Torvalds 	sbuff = devip->sense_buff;
975c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
976c65b1445SDouglas Gilbert 		if (want_dsense) {
977c65b1445SDouglas Gilbert 			arr[0] = 0x72;
978c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
979c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
980c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
981c65b1445SDouglas Gilbert 		} else {
982c65b1445SDouglas Gilbert 			arr[0] = 0x70;
983c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
984c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
985c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
986c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
987c65b1445SDouglas Gilbert 		}
988c65b1445SDouglas Gilbert 	} else {
989c65b1445SDouglas Gilbert 		memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
9901da177e4SLinus Torvalds 		if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
9911da177e4SLinus Torvalds 			/* DESC bit set and sense_buff in fixed format */
992c65b1445SDouglas Gilbert 			memset(arr, 0, sizeof(arr));
9931da177e4SLinus Torvalds 			arr[0] = 0x72;
9941da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
9951da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
9961da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
9971da177e4SLinus Torvalds 			len = 8;
998c65b1445SDouglas Gilbert 		}
999c65b1445SDouglas Gilbert 	}
1000c65b1445SDouglas Gilbert 	mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
10011da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
10021da177e4SLinus Torvalds }
10031da177e4SLinus Torvalds 
1004c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp,
1005c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
1006c65b1445SDouglas Gilbert {
1007c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1008c65b1445SDouglas Gilbert 	int power_cond, errsts, start;
1009c65b1445SDouglas Gilbert 
1010c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1011c65b1445SDouglas Gilbert 		return errsts;
1012c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1013c65b1445SDouglas Gilbert 	if (power_cond) {
1014c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1015c65b1445SDouglas Gilbert 			       	0);
1016c65b1445SDouglas Gilbert 		return check_condition_result;
1017c65b1445SDouglas Gilbert 	}
1018c65b1445SDouglas Gilbert 	start = cmd[4] & 1;
1019c65b1445SDouglas Gilbert 	if (start == devip->stopped)
1020c65b1445SDouglas Gilbert 		devip->stopped = !start;
1021c65b1445SDouglas Gilbert 	return 0;
1022c65b1445SDouglas Gilbert }
1023c65b1445SDouglas Gilbert 
102428898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
102528898873SFUJITA Tomonori {
102628898873SFUJITA Tomonori 	if (scsi_debug_virtual_gb > 0)
10275447ed6cSDouglas Gilbert 		return (sector_t)scsi_debug_virtual_gb *
10285447ed6cSDouglas Gilbert 			(1073741824 / scsi_debug_sector_size);
102928898873SFUJITA Tomonori 	else
103028898873SFUJITA Tomonori 		return sdebug_store_sectors;
103128898873SFUJITA Tomonori }
103228898873SFUJITA Tomonori 
10331da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
10341da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp,
10351da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
10361da177e4SLinus Torvalds {
10371da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1038c65b1445SDouglas Gilbert 	unsigned int capac;
10391da177e4SLinus Torvalds 	int errsts;
10401da177e4SLinus Torvalds 
1041c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
10421da177e4SLinus Torvalds 		return errsts;
1043c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
104428898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
10451da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1046c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1047c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
10481da177e4SLinus Torvalds 		arr[0] = (capac >> 24);
10491da177e4SLinus Torvalds 		arr[1] = (capac >> 16) & 0xff;
10501da177e4SLinus Torvalds 		arr[2] = (capac >> 8) & 0xff;
10511da177e4SLinus Torvalds 		arr[3] = capac & 0xff;
1052c65b1445SDouglas Gilbert 	} else {
1053c65b1445SDouglas Gilbert 		arr[0] = 0xff;
1054c65b1445SDouglas Gilbert 		arr[1] = 0xff;
1055c65b1445SDouglas Gilbert 		arr[2] = 0xff;
1056c65b1445SDouglas Gilbert 		arr[3] = 0xff;
1057c65b1445SDouglas Gilbert 	}
1058597136abSMartin K. Petersen 	arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
1059597136abSMartin K. Petersen 	arr[7] = scsi_debug_sector_size & 0xff;
10601da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
10611da177e4SLinus Torvalds }
10621da177e4SLinus Torvalds 
1063c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1064c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp,
1065c65b1445SDouglas Gilbert 			  struct sdebug_dev_info * devip)
1066c65b1445SDouglas Gilbert {
1067c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1068c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1069c65b1445SDouglas Gilbert 	unsigned long long capac;
1070c65b1445SDouglas Gilbert 	int errsts, k, alloc_len;
1071c65b1445SDouglas Gilbert 
1072c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1073c65b1445SDouglas Gilbert 		return errsts;
1074c65b1445SDouglas Gilbert 	alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1075c65b1445SDouglas Gilbert 		     + cmd[13]);
1076c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
107728898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1078c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1079c65b1445SDouglas Gilbert 	capac = sdebug_capacity - 1;
1080c65b1445SDouglas Gilbert 	for (k = 0; k < 8; ++k, capac >>= 8)
1081c65b1445SDouglas Gilbert 		arr[7 - k] = capac & 0xff;
1082597136abSMartin K. Petersen 	arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
1083597136abSMartin K. Petersen 	arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
1084597136abSMartin K. Petersen 	arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
1085597136abSMartin K. Petersen 	arr[11] = scsi_debug_sector_size & 0xff;
1086ea61fca5SMartin K. Petersen 	arr[13] = scsi_debug_physblk_exp & 0xf;
1087ea61fca5SMartin K. Petersen 	arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
108844d92694SMartin K. Petersen 
1089be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
10905b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1091be1dd78dSEric Sandeen 		if (scsi_debug_lbprz)
1092be1dd78dSEric Sandeen 			arr[14] |= 0x40; /* LBPRZ */
1093be1dd78dSEric Sandeen 	}
109444d92694SMartin K. Petersen 
1095ea61fca5SMartin K. Petersen 	arr[15] = scsi_debug_lowest_aligned & 0xff;
1096c6a44287SMartin K. Petersen 
1097c6a44287SMartin K. Petersen 	if (scsi_debug_dif) {
1098c6a44287SMartin K. Petersen 		arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
1099c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1100c6a44287SMartin K. Petersen 	}
1101c6a44287SMartin K. Petersen 
1102c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1103c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1104c65b1445SDouglas Gilbert }
1105c65b1445SDouglas Gilbert 
11065a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
11075a09e398SHannes Reinecke 
11085a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp,
11095a09e398SHannes Reinecke 			      struct sdebug_dev_info * devip)
11105a09e398SHannes Reinecke {
11115a09e398SHannes Reinecke 	unsigned char *cmd = (unsigned char *)scp->cmnd;
11125a09e398SHannes Reinecke 	unsigned char * arr;
11135a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
11145a09e398SHannes Reinecke 	int n, ret, alen, rlen;
11155a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
11165a09e398SHannes Reinecke 
11175a09e398SHannes Reinecke 	alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
11185a09e398SHannes Reinecke 		+ cmd[9]);
11195a09e398SHannes Reinecke 
11206f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
11216f3cbf55SDouglas Gilbert 	if (! arr)
11226f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
11235a09e398SHannes Reinecke 	/*
11245a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
11255a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
11265a09e398SHannes Reinecke 	 * So we create two port groups with one port each
11275a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
11285a09e398SHannes Reinecke 	 */
11295a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
11305a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
11315a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
11325a09e398SHannes Reinecke 	    (devip->channel & 0x7f);
11335a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
11345a09e398SHannes Reinecke 	    (devip->channel & 0x7f) + 0x80;
11355a09e398SHannes Reinecke 
11365a09e398SHannes Reinecke 	/*
11375a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
11385a09e398SHannes Reinecke 	 */
11395a09e398SHannes Reinecke 	n = 4;
11405a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno) {
11415a09e398SHannes Reinecke 	    arr[n++] = host_no % 3; /* Asymm access state */
11425a09e398SHannes Reinecke 	    arr[n++] = 0x0F; /* claim: all states are supported */
11435a09e398SHannes Reinecke 	} else {
11445a09e398SHannes Reinecke 	    arr[n++] = 0x0; /* Active/Optimized path */
11455a09e398SHannes Reinecke 	    arr[n++] = 0x01; /* claim: only support active/optimized paths */
11465a09e398SHannes Reinecke 	}
11475a09e398SHannes Reinecke 	arr[n++] = (port_group_a >> 8) & 0xff;
11485a09e398SHannes Reinecke 	arr[n++] = port_group_a & 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_a >> 8) & 0xff;
11565a09e398SHannes Reinecke 	arr[n++] = port_a & 0xff;
11575a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
11585a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
11595a09e398SHannes Reinecke 	arr[n++] = (port_group_b >> 8) & 0xff;
11605a09e398SHannes Reinecke 	arr[n++] = port_group_b & 0xff;
11615a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11625a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
11635a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
11645a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
11655a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11665a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11675a09e398SHannes Reinecke 	arr[n++] = (port_b >> 8) & 0xff;
11685a09e398SHannes Reinecke 	arr[n++] = port_b & 0xff;
11695a09e398SHannes Reinecke 
11705a09e398SHannes Reinecke 	rlen = n - 4;
11715a09e398SHannes Reinecke 	arr[0] = (rlen >> 24) & 0xff;
11725a09e398SHannes Reinecke 	arr[1] = (rlen >> 16) & 0xff;
11735a09e398SHannes Reinecke 	arr[2] = (rlen >> 8) & 0xff;
11745a09e398SHannes Reinecke 	arr[3] = rlen & 0xff;
11755a09e398SHannes Reinecke 
11765a09e398SHannes Reinecke 	/*
11775a09e398SHannes Reinecke 	 * Return the smallest value of either
11785a09e398SHannes Reinecke 	 * - The allocated length
11795a09e398SHannes Reinecke 	 * - The constructed command length
11805a09e398SHannes Reinecke 	 * - The maximum array size
11815a09e398SHannes Reinecke 	 */
11825a09e398SHannes Reinecke 	rlen = min(alen,n);
11835a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
11845a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
11855a09e398SHannes Reinecke 	kfree(arr);
11865a09e398SHannes Reinecke 	return ret;
11875a09e398SHannes Reinecke }
11885a09e398SHannes Reinecke 
11891da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
11901da177e4SLinus Torvalds 
11911da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
11921da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
11931da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
11941da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
11951da177e4SLinus Torvalds 
11961da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
11971da177e4SLinus Torvalds 	if (1 == pcontrol)
11981da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
11991da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
12001da177e4SLinus Torvalds }
12011da177e4SLinus Torvalds 
12021da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
12031da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
12041da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
12051da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
12061da177e4SLinus Torvalds 
12071da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
12081da177e4SLinus Torvalds 	if (1 == pcontrol)
12091da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
12101da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
12111da177e4SLinus Torvalds }
12121da177e4SLinus Torvalds 
12131da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target)
12141da177e4SLinus Torvalds {       /* Format device page for mode_sense */
12151da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
12161da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
12171da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
12181da177e4SLinus Torvalds 
12191da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
12201da177e4SLinus Torvalds 	p[10] = (sdebug_sectors_per >> 8) & 0xff;
12211da177e4SLinus Torvalds 	p[11] = sdebug_sectors_per & 0xff;
1222597136abSMartin K. Petersen 	p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1223597136abSMartin K. Petersen 	p[13] = scsi_debug_sector_size & 0xff;
1224d986788bSMartin Pitt 	if (scsi_debug_removable)
12251da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
12261da177e4SLinus Torvalds 	if (1 == pcontrol)
12271da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
12281da177e4SLinus Torvalds 	return sizeof(format_pg);
12291da177e4SLinus Torvalds }
12301da177e4SLinus Torvalds 
12311da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
12321da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
12331da177e4SLinus Torvalds 	unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
12341da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
12351da177e4SLinus Torvalds 
12361da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
12371da177e4SLinus Torvalds 	if (1 == pcontrol)
12381da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(caching_pg) - 2);
12391da177e4SLinus Torvalds 	return sizeof(caching_pg);
12401da177e4SLinus Torvalds }
12411da177e4SLinus Torvalds 
12421da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
12431da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
1244c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1245c65b1445SDouglas Gilbert 				        0, 0, 0, 0};
1246c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
12471da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
12481da177e4SLinus Torvalds 
12491da177e4SLinus Torvalds 	if (scsi_debug_dsense)
12501da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
1251c65b1445SDouglas Gilbert 	else
1252c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
1253c6a44287SMartin K. Petersen 
1254c6a44287SMartin K. Petersen 	if (scsi_debug_ato)
1255c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1256c6a44287SMartin K. Petersen 
12571da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
12581da177e4SLinus Torvalds 	if (1 == pcontrol)
1259c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1260c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1261c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
12621da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
12631da177e4SLinus Torvalds }
12641da177e4SLinus Torvalds 
1265c65b1445SDouglas Gilbert 
12661da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
12671da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
1268c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
12691da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
1270c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1271c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
1272c65b1445SDouglas Gilbert 
12731da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
12741da177e4SLinus Torvalds 	if (1 == pcontrol)
1275c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1276c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1277c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
12781da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
12791da177e4SLinus Torvalds }
12801da177e4SLinus Torvalds 
1281c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1282c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
1283c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1284c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1285c65b1445SDouglas Gilbert 
1286c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1287c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1288c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1289c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
1290c65b1445SDouglas Gilbert }
1291c65b1445SDouglas Gilbert 
1292c65b1445SDouglas Gilbert 
1293c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1294c65b1445SDouglas Gilbert 			      int target_dev_id)
1295c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
1296c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1297c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1298c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1299c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1300c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
1301c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1302c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1303c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1304c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1305c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1306c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
1307c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1308c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1309c65b1445SDouglas Gilbert 		};
1310c65b1445SDouglas Gilbert 	int port_a, port_b;
1311c65b1445SDouglas Gilbert 
1312c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1313c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1314c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1315c65b1445SDouglas Gilbert 	p[20] = (port_a >> 24);
1316c65b1445SDouglas Gilbert 	p[21] = (port_a >> 16) & 0xff;
1317c65b1445SDouglas Gilbert 	p[22] = (port_a >> 8) & 0xff;
1318c65b1445SDouglas Gilbert 	p[23] = port_a & 0xff;
1319c65b1445SDouglas Gilbert 	p[48 + 20] = (port_b >> 24);
1320c65b1445SDouglas Gilbert 	p[48 + 21] = (port_b >> 16) & 0xff;
1321c65b1445SDouglas Gilbert 	p[48 + 22] = (port_b >> 8) & 0xff;
1322c65b1445SDouglas Gilbert 	p[48 + 23] = port_b & 0xff;
1323c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1324c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1325c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
1326c65b1445SDouglas Gilbert }
1327c65b1445SDouglas Gilbert 
1328c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1329c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
1330c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1331c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1332c65b1445SDouglas Gilbert 		};
1333c65b1445SDouglas Gilbert 
1334c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1335c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1336c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1337c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
1338c65b1445SDouglas Gilbert }
1339c65b1445SDouglas Gilbert 
13401da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
13411da177e4SLinus Torvalds 
13421da177e4SLinus Torvalds static int resp_mode_sense(struct scsi_cmnd * scp, int target,
13431da177e4SLinus Torvalds 			   struct sdebug_dev_info * devip)
13441da177e4SLinus Torvalds {
134523183910SDouglas Gilbert 	unsigned char dbd, llbaa;
134623183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
13471da177e4SLinus Torvalds 	unsigned char dev_spec;
134823183910SDouglas Gilbert 	int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
13491da177e4SLinus Torvalds 	unsigned char * ap;
13501da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
13511da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
13521da177e4SLinus Torvalds 
1353c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
13541da177e4SLinus Torvalds 		return errsts;
135523183910SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);
13561da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
13571da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
13581da177e4SLinus Torvalds 	subpcode = cmd[3];
13591da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
136023183910SDouglas Gilbert 	llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
136123183910SDouglas Gilbert 	if ((0 == scsi_debug_ptype) && (0 == dbd))
136223183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
136323183910SDouglas Gilbert 	else
136423183910SDouglas Gilbert 		bd_len = 0;
13651da177e4SLinus Torvalds 	alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
13661da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
13671da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
13681da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
13691da177e4SLinus Torvalds 			       	0);
13701da177e4SLinus Torvalds 		return check_condition_result;
13711da177e4SLinus Torvalds 	}
1372c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1373c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
137423183910SDouglas Gilbert 	/* set DPOFUA bit for disks */
137523183910SDouglas Gilbert 	if (0 == scsi_debug_ptype)
137623183910SDouglas Gilbert 		dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
137723183910SDouglas Gilbert 	else
137823183910SDouglas Gilbert 		dev_spec = 0x0;
13791da177e4SLinus Torvalds 	if (msense_6) {
13801da177e4SLinus Torvalds 		arr[2] = dev_spec;
138123183910SDouglas Gilbert 		arr[3] = bd_len;
13821da177e4SLinus Torvalds 		offset = 4;
13831da177e4SLinus Torvalds 	} else {
13841da177e4SLinus Torvalds 		arr[3] = dev_spec;
138523183910SDouglas Gilbert 		if (16 == bd_len)
138623183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
138723183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
13881da177e4SLinus Torvalds 		offset = 8;
13891da177e4SLinus Torvalds 	}
13901da177e4SLinus Torvalds 	ap = arr + offset;
139128898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
139228898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
139328898873SFUJITA Tomonori 
139423183910SDouglas Gilbert 	if (8 == bd_len) {
139523183910SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe) {
139623183910SDouglas Gilbert 			ap[0] = 0xff;
139723183910SDouglas Gilbert 			ap[1] = 0xff;
139823183910SDouglas Gilbert 			ap[2] = 0xff;
139923183910SDouglas Gilbert 			ap[3] = 0xff;
140023183910SDouglas Gilbert 		} else {
140123183910SDouglas Gilbert 			ap[0] = (sdebug_capacity >> 24) & 0xff;
140223183910SDouglas Gilbert 			ap[1] = (sdebug_capacity >> 16) & 0xff;
140323183910SDouglas Gilbert 			ap[2] = (sdebug_capacity >> 8) & 0xff;
140423183910SDouglas Gilbert 			ap[3] = sdebug_capacity & 0xff;
140523183910SDouglas Gilbert 		}
1406597136abSMartin K. Petersen 		ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1407597136abSMartin K. Petersen 		ap[7] = scsi_debug_sector_size & 0xff;
140823183910SDouglas Gilbert 		offset += bd_len;
140923183910SDouglas Gilbert 		ap = arr + offset;
141023183910SDouglas Gilbert 	} else if (16 == bd_len) {
141123183910SDouglas Gilbert 		unsigned long long capac = sdebug_capacity;
141223183910SDouglas Gilbert 
141323183910SDouglas Gilbert         	for (k = 0; k < 8; ++k, capac >>= 8)
141423183910SDouglas Gilbert                 	ap[7 - k] = capac & 0xff;
1415597136abSMartin K. Petersen 		ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1416597136abSMartin K. Petersen 		ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1417597136abSMartin K. Petersen 		ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1418597136abSMartin K. Petersen 		ap[15] = scsi_debug_sector_size & 0xff;
141923183910SDouglas Gilbert 		offset += bd_len;
142023183910SDouglas Gilbert 		ap = arr + offset;
142123183910SDouglas Gilbert 	}
14221da177e4SLinus Torvalds 
1423c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1424c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
14251da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
14261da177e4SLinus Torvalds 			       	0);
14271da177e4SLinus Torvalds 		return check_condition_result;
14281da177e4SLinus Torvalds 	}
14291da177e4SLinus Torvalds 	switch (pcode) {
14301da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
14311da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
14321da177e4SLinus Torvalds 		offset += len;
14331da177e4SLinus Torvalds 		break;
14341da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
14351da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
14361da177e4SLinus Torvalds 		offset += len;
14371da177e4SLinus Torvalds 		break;
14381da177e4SLinus Torvalds         case 0x3:       /* Format device page, direct access */
14391da177e4SLinus Torvalds                 len = resp_format_pg(ap, pcontrol, target);
14401da177e4SLinus Torvalds                 offset += len;
14411da177e4SLinus Torvalds                 break;
14421da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
14431da177e4SLinus Torvalds 		len = resp_caching_pg(ap, pcontrol, target);
14441da177e4SLinus Torvalds 		offset += len;
14451da177e4SLinus Torvalds 		break;
14461da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
14471da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
14481da177e4SLinus Torvalds 		offset += len;
14491da177e4SLinus Torvalds 		break;
1450c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
1451c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
1452c65b1445SDouglas Gilbert 		        mk_sense_buffer(devip, ILLEGAL_REQUEST,
1453c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1454c65b1445SDouglas Gilbert 			return check_condition_result;
1455c65b1445SDouglas Gilbert 	        }
1456c65b1445SDouglas Gilbert 		len = 0;
1457c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
1458c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1459c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
1460c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1461c65b1445SDouglas Gilbert 						  target_dev_id);
1462c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
1463c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
1464c65b1445SDouglas Gilbert 		offset += len;
1465c65b1445SDouglas Gilbert 		break;
14661da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
14671da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
14681da177e4SLinus Torvalds 		offset += len;
14691da177e4SLinus Torvalds 		break;
14701da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
1471c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
14721da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
14731da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
14741da177e4SLinus Torvalds 			len += resp_format_pg(ap + len, pcontrol, target);
14751da177e4SLinus Torvalds 			len += resp_caching_pg(ap + len, pcontrol, target);
14761da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1477c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1478c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
1479c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1480c65b1445SDouglas Gilbert 						  target, target_dev_id);
1481c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
1482c65b1445SDouglas Gilbert 			}
14831da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
1484c65b1445SDouglas Gilbert 		} else {
1485c65b1445SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
1486c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1487c65b1445SDouglas Gilbert 			return check_condition_result;
1488c65b1445SDouglas Gilbert                 }
14891da177e4SLinus Torvalds 		offset += len;
14901da177e4SLinus Torvalds 		break;
14911da177e4SLinus Torvalds 	default:
14921da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
14931da177e4SLinus Torvalds 			       	0);
14941da177e4SLinus Torvalds 		return check_condition_result;
14951da177e4SLinus Torvalds 	}
14961da177e4SLinus Torvalds 	if (msense_6)
14971da177e4SLinus Torvalds 		arr[0] = offset - 1;
14981da177e4SLinus Torvalds 	else {
14991da177e4SLinus Torvalds 		arr[0] = ((offset - 2) >> 8) & 0xff;
15001da177e4SLinus Torvalds 		arr[1] = (offset - 2) & 0xff;
15011da177e4SLinus Torvalds 	}
15021da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
15031da177e4SLinus Torvalds }
15041da177e4SLinus Torvalds 
1505c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
1506c65b1445SDouglas Gilbert 
1507c65b1445SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1508c65b1445SDouglas Gilbert 			    struct sdebug_dev_info * devip)
1509c65b1445SDouglas Gilbert {
1510c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1511c65b1445SDouglas Gilbert 	int param_len, res, errsts, mpage;
1512c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1513c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1514c65b1445SDouglas Gilbert 
1515c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1516c65b1445SDouglas Gilbert 		return errsts;
1517c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1518c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
1519c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
1520c65b1445SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1521c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1522c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1523c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
1524c65b1445SDouglas Gilbert 		return check_condition_result;
1525c65b1445SDouglas Gilbert 	}
1526c65b1445SDouglas Gilbert         res = fetch_to_dev_buffer(scp, arr, param_len);
1527c65b1445SDouglas Gilbert         if (-1 == res)
1528c65b1445SDouglas Gilbert                 return (DID_ERROR << 16);
1529c65b1445SDouglas Gilbert         else if ((res < param_len) &&
1530c65b1445SDouglas Gilbert                  (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1531c65b1445SDouglas Gilbert                 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1532c65b1445SDouglas Gilbert                        " IO sent=%d bytes\n", param_len, res);
1533c65b1445SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1534c65b1445SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
153523183910SDouglas Gilbert 	if (md_len > 2) {
1536c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1537c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_PARAM_LIST, 0);
1538c65b1445SDouglas Gilbert 		return check_condition_result;
1539c65b1445SDouglas Gilbert 	}
1540c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
1541c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
1542c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
1543c65b1445SDouglas Gilbert 	if (ps) {
1544c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1545c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_PARAM_LIST, 0);
1546c65b1445SDouglas Gilbert 		return check_condition_result;
1547c65b1445SDouglas Gilbert 	}
1548c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
1549c65b1445SDouglas Gilbert 	pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1550c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
1551c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
1552c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1553c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
1554c65b1445SDouglas Gilbert 		return check_condition_result;
1555c65b1445SDouglas Gilbert 	}
1556c65b1445SDouglas Gilbert 	switch (mpage) {
1557c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
1558c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
1559c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
1560c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
1561c65b1445SDouglas Gilbert 			scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1562c65b1445SDouglas Gilbert 			return 0;
1563c65b1445SDouglas Gilbert 		}
1564c65b1445SDouglas Gilbert 		break;
1565c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
1566c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
1567c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
1568c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
1569c65b1445SDouglas Gilbert 			return 0;
1570c65b1445SDouglas Gilbert 		}
1571c65b1445SDouglas Gilbert 		break;
1572c65b1445SDouglas Gilbert 	default:
1573c65b1445SDouglas Gilbert 		break;
1574c65b1445SDouglas Gilbert 	}
1575c65b1445SDouglas Gilbert 	mk_sense_buffer(devip, ILLEGAL_REQUEST,
1576c65b1445SDouglas Gilbert 			INVALID_FIELD_IN_PARAM_LIST, 0);
1577c65b1445SDouglas Gilbert 	return check_condition_result;
1578c65b1445SDouglas Gilbert }
1579c65b1445SDouglas Gilbert 
1580c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr)
1581c65b1445SDouglas Gilbert {
1582c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1583c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
1584c65b1445SDouglas Gilbert 		};
1585c65b1445SDouglas Gilbert 
1586c65b1445SDouglas Gilbert         memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1587c65b1445SDouglas Gilbert         return sizeof(temp_l_pg);
1588c65b1445SDouglas Gilbert }
1589c65b1445SDouglas Gilbert 
1590c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr)
1591c65b1445SDouglas Gilbert {
1592c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1593c65b1445SDouglas Gilbert 		};
1594c65b1445SDouglas Gilbert 
1595c65b1445SDouglas Gilbert         memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1596c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
1597c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
1598c65b1445SDouglas Gilbert 		arr[5] = 0xff;
1599c65b1445SDouglas Gilbert 	}
1600c65b1445SDouglas Gilbert         return sizeof(ie_l_pg);
1601c65b1445SDouglas Gilbert }
1602c65b1445SDouglas Gilbert 
1603c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
1604c65b1445SDouglas Gilbert 
1605c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp,
1606c65b1445SDouglas Gilbert                           struct sdebug_dev_info * devip)
1607c65b1445SDouglas Gilbert {
160823183910SDouglas Gilbert 	int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
1609c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1610c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1611c65b1445SDouglas Gilbert 
1612c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1613c65b1445SDouglas Gilbert 		return errsts;
1614c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1615c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
1616c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
1617c65b1445SDouglas Gilbert 	if (ppc || sp) {
1618c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1619c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
1620c65b1445SDouglas Gilbert 		return check_condition_result;
1621c65b1445SDouglas Gilbert 	}
1622c65b1445SDouglas Gilbert 	pcontrol = (cmd[2] & 0xc0) >> 6;
1623c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
162423183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
1625c65b1445SDouglas Gilbert 	alloc_len = (cmd[7] << 8) + cmd[8];
1626c65b1445SDouglas Gilbert 	arr[0] = pcode;
162723183910SDouglas Gilbert 	if (0 == subpcode) {
1628c65b1445SDouglas Gilbert 		switch (pcode) {
1629c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
1630c65b1445SDouglas Gilbert 			n = 4;
1631c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
1632c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
1633c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
1634c65b1445SDouglas Gilbert 			arr[3] = n - 4;
1635c65b1445SDouglas Gilbert 			break;
1636c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
1637c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
1638c65b1445SDouglas Gilbert 			break;
1639c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
1640c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
1641c65b1445SDouglas Gilbert 			break;
1642c65b1445SDouglas Gilbert 		default:
1643c65b1445SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
1644c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1645c65b1445SDouglas Gilbert 			return check_condition_result;
1646c65b1445SDouglas Gilbert 		}
164723183910SDouglas Gilbert 	} else if (0xff == subpcode) {
164823183910SDouglas Gilbert 		arr[0] |= 0x40;
164923183910SDouglas Gilbert 		arr[1] = subpcode;
165023183910SDouglas Gilbert 		switch (pcode) {
165123183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
165223183910SDouglas Gilbert 			n = 4;
165323183910SDouglas Gilbert 			arr[n++] = 0x0;
165423183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
165523183910SDouglas Gilbert 			arr[n++] = 0x0;
165623183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
165723183910SDouglas Gilbert 			arr[n++] = 0xd;
165823183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
165923183910SDouglas Gilbert 			arr[n++] = 0x2f;
166023183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
166123183910SDouglas Gilbert 			arr[3] = n - 4;
166223183910SDouglas Gilbert 			break;
166323183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
166423183910SDouglas Gilbert 			n = 4;
166523183910SDouglas Gilbert 			arr[n++] = 0xd;
166623183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
166723183910SDouglas Gilbert 			arr[3] = n - 4;
166823183910SDouglas Gilbert 			break;
166923183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
167023183910SDouglas Gilbert 			n = 4;
167123183910SDouglas Gilbert 			arr[n++] = 0x2f;
167223183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
167323183910SDouglas Gilbert 			arr[3] = n - 4;
167423183910SDouglas Gilbert 			break;
167523183910SDouglas Gilbert 		default:
167623183910SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
167723183910SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
167823183910SDouglas Gilbert 			return check_condition_result;
167923183910SDouglas Gilbert 		}
168023183910SDouglas Gilbert 	} else {
168123183910SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
168223183910SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
168323183910SDouglas Gilbert 		return check_condition_result;
168423183910SDouglas Gilbert 	}
1685c65b1445SDouglas Gilbert 	len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1686c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1687c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
1688c65b1445SDouglas Gilbert }
1689c65b1445SDouglas Gilbert 
169019789100SFUJITA Tomonori static int check_device_access_params(struct sdebug_dev_info *devi,
169119789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
16921da177e4SLinus Torvalds {
1693c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
169419789100SFUJITA Tomonori 		mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
16951da177e4SLinus Torvalds 		return check_condition_result;
16961da177e4SLinus Torvalds 	}
1697c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
1698c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
169919789100SFUJITA Tomonori 		mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
1700c65b1445SDouglas Gilbert 		return check_condition_result;
1701c65b1445SDouglas Gilbert 	}
170219789100SFUJITA Tomonori 	return 0;
170319789100SFUJITA Tomonori }
170419789100SFUJITA Tomonori 
1705a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
170619789100SFUJITA Tomonori static int do_device_access(struct scsi_cmnd *scmd,
170719789100SFUJITA Tomonori 			    struct sdebug_dev_info *devi,
170819789100SFUJITA Tomonori 			    unsigned long long lba, unsigned int num, int write)
170919789100SFUJITA Tomonori {
171019789100SFUJITA Tomonori 	int ret;
1711a361cc00SDarrick J. Wong 	unsigned long long block, rest = 0;
1712a4517511SAkinobu Mita 	struct scsi_data_buffer *sdb;
1713a4517511SAkinobu Mita 	enum dma_data_direction dir;
1714a4517511SAkinobu Mita 	size_t (*func)(struct scatterlist *, unsigned int, void *, size_t,
1715a4517511SAkinobu Mita 		       off_t);
171619789100SFUJITA Tomonori 
1717a4517511SAkinobu Mita 	if (write) {
1718a4517511SAkinobu Mita 		sdb = scsi_out(scmd);
1719a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
1720a4517511SAkinobu Mita 		func = sg_pcopy_to_buffer;
1721a4517511SAkinobu Mita 	} else {
1722a4517511SAkinobu Mita 		sdb = scsi_in(scmd);
1723a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
1724a4517511SAkinobu Mita 		func = sg_pcopy_from_buffer;
1725a4517511SAkinobu Mita 	}
1726a4517511SAkinobu Mita 
1727a4517511SAkinobu Mita 	if (!sdb->length)
1728a4517511SAkinobu Mita 		return 0;
1729a4517511SAkinobu Mita 	if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
1730a4517511SAkinobu Mita 		return -1;
173119789100SFUJITA Tomonori 
173219789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
173319789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
173419789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
173519789100SFUJITA Tomonori 
1736a4517511SAkinobu Mita 	ret = func(sdb->table.sgl, sdb->table.nents,
1737a4517511SAkinobu Mita 		   fake_storep + (block * scsi_debug_sector_size),
1738a4517511SAkinobu Mita 		   (num - rest) * scsi_debug_sector_size, 0);
1739a4517511SAkinobu Mita 	if (ret != (num - rest) * scsi_debug_sector_size)
1740a4517511SAkinobu Mita 		return ret;
1741a4517511SAkinobu Mita 
1742a4517511SAkinobu Mita 	if (rest) {
1743a4517511SAkinobu Mita 		ret += func(sdb->table.sgl, sdb->table.nents,
1744a4517511SAkinobu Mita 			    fake_storep, rest * scsi_debug_sector_size,
1745597136abSMartin K. Petersen 			    (num - rest) * scsi_debug_sector_size);
1746a4517511SAkinobu Mita 	}
174719789100SFUJITA Tomonori 
174819789100SFUJITA Tomonori 	return ret;
174919789100SFUJITA Tomonori }
175019789100SFUJITA Tomonori 
175151d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
1752beb40ea4SAkinobu Mita {
175351d648afSAkinobu Mita 	__be16 csum;
1754beb40ea4SAkinobu Mita 
175551d648afSAkinobu Mita 	if (scsi_debug_guard)
175651d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
175751d648afSAkinobu Mita 	else
1758beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
175951d648afSAkinobu Mita 
1760beb40ea4SAkinobu Mita 	return csum;
1761beb40ea4SAkinobu Mita }
1762beb40ea4SAkinobu Mita 
1763beb40ea4SAkinobu Mita static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
1764beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
1765beb40ea4SAkinobu Mita {
176651d648afSAkinobu Mita 	__be16 csum = dif_compute_csum(data, scsi_debug_sector_size);
1767beb40ea4SAkinobu Mita 
1768beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
1769beb40ea4SAkinobu Mita 		pr_err("%s: GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
1770beb40ea4SAkinobu Mita 			__func__,
1771beb40ea4SAkinobu Mita 			(unsigned long)sector,
1772beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
1773beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
1774beb40ea4SAkinobu Mita 		return 0x01;
1775beb40ea4SAkinobu Mita 	}
1776beb40ea4SAkinobu Mita 	if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
1777beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
1778beb40ea4SAkinobu Mita 		pr_err("%s: REF check failed on sector %lu\n",
1779beb40ea4SAkinobu Mita 			__func__, (unsigned long)sector);
1780beb40ea4SAkinobu Mita 		return 0x03;
1781beb40ea4SAkinobu Mita 	}
1782beb40ea4SAkinobu Mita 	if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1783beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
1784beb40ea4SAkinobu Mita 		pr_err("%s: REF check failed on sector %lu\n",
1785beb40ea4SAkinobu Mita 			__func__, (unsigned long)sector);
1786beb40ea4SAkinobu Mita 		return 0x03;
1787beb40ea4SAkinobu Mita 	}
1788beb40ea4SAkinobu Mita 	return 0;
1789beb40ea4SAkinobu Mita }
1790beb40ea4SAkinobu Mita 
1791bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
179265f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
1793c6a44287SMartin K. Petersen {
1794be4e11beSAkinobu Mita 	size_t resid;
1795c6a44287SMartin K. Petersen 	void *paddr;
179614faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
1797be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
1798c6a44287SMartin K. Petersen 
1799e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
1800e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
1801c6a44287SMartin K. Petersen 
1802be4e11beSAkinobu Mita 	sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
1803be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
1804be4e11beSAkinobu Mita 			(read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
1805be4e11beSAkinobu Mita 
1806be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
1807be4e11beSAkinobu Mita 		size_t len = min(miter.length, resid);
180814faa944SAkinobu Mita 		void *start = dif_store(sector);
1809be4e11beSAkinobu Mita 		size_t rest = 0;
181014faa944SAkinobu Mita 
181114faa944SAkinobu Mita 		if (dif_store_end < start + len)
181214faa944SAkinobu Mita 			rest = start + len - dif_store_end;
1813c6a44287SMartin K. Petersen 
1814be4e11beSAkinobu Mita 		paddr = miter.addr;
181514faa944SAkinobu Mita 
181665f72f2aSAkinobu Mita 		if (read)
181765f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
181865f72f2aSAkinobu Mita 		else
181965f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
182065f72f2aSAkinobu Mita 
182165f72f2aSAkinobu Mita 		if (rest) {
182265f72f2aSAkinobu Mita 			if (read)
182314faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
182465f72f2aSAkinobu Mita 			else
182565f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
182665f72f2aSAkinobu Mita 		}
1827c6a44287SMartin K. Petersen 
1828e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
1829c6a44287SMartin K. Petersen 		resid -= len;
1830c6a44287SMartin K. Petersen 	}
1831be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
1832bb8c063cSAkinobu Mita }
1833c6a44287SMartin K. Petersen 
1834bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
1835bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
1836bb8c063cSAkinobu Mita {
1837bb8c063cSAkinobu Mita 	unsigned int i;
1838bb8c063cSAkinobu Mita 	struct sd_dif_tuple *sdt;
1839bb8c063cSAkinobu Mita 	sector_t sector;
1840bb8c063cSAkinobu Mita 
1841c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
1842bb8c063cSAkinobu Mita 		int ret;
1843bb8c063cSAkinobu Mita 
1844bb8c063cSAkinobu Mita 		sector = start_sec + i;
1845bb8c063cSAkinobu Mita 		sdt = dif_store(sector);
1846bb8c063cSAkinobu Mita 
184751d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
1848bb8c063cSAkinobu Mita 			continue;
1849bb8c063cSAkinobu Mita 
1850bb8c063cSAkinobu Mita 		ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
1851bb8c063cSAkinobu Mita 		if (ret) {
1852bb8c063cSAkinobu Mita 			dif_errors++;
1853bb8c063cSAkinobu Mita 			return ret;
1854bb8c063cSAkinobu Mita 		}
1855bb8c063cSAkinobu Mita 	}
1856bb8c063cSAkinobu Mita 
185765f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, true);
1858c6a44287SMartin K. Petersen 	dix_reads++;
1859c6a44287SMartin K. Petersen 
1860c6a44287SMartin K. Petersen 	return 0;
1861c6a44287SMartin K. Petersen }
1862c6a44287SMartin K. Petersen 
186319789100SFUJITA Tomonori static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
1864395cef03SMartin K. Petersen 		     unsigned int num, struct sdebug_dev_info *devip,
1865395cef03SMartin K. Petersen 		     u32 ei_lba)
186619789100SFUJITA Tomonori {
186719789100SFUJITA Tomonori 	unsigned long iflags;
186819789100SFUJITA Tomonori 	int ret;
186919789100SFUJITA Tomonori 
187019789100SFUJITA Tomonori 	ret = check_device_access_params(devip, lba, num);
187119789100SFUJITA Tomonori 	if (ret)
187219789100SFUJITA Tomonori 		return ret;
187319789100SFUJITA Tomonori 
18741da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
187532f7ef73SDouglas Gilbert 	    (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
1876c65b1445SDouglas Gilbert 	    ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1877c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
187832f7ef73SDouglas Gilbert 		mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
1879c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
1880c65b1445SDouglas Gilbert 		if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1881c65b1445SDouglas Gilbert 			devip->sense_buff[0] |= 0x80;	/* Valid bit */
188232f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
188332f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
1884c65b1445SDouglas Gilbert 			devip->sense_buff[3] = (ret >> 24) & 0xff;
1885c65b1445SDouglas Gilbert 			devip->sense_buff[4] = (ret >> 16) & 0xff;
1886c65b1445SDouglas Gilbert 			devip->sense_buff[5] = (ret >> 8) & 0xff;
1887c65b1445SDouglas Gilbert 			devip->sense_buff[6] = ret & 0xff;
1888c65b1445SDouglas Gilbert 		}
1889a87e3a67SDouglas Gilbert 	        scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
18901da177e4SLinus Torvalds 		return check_condition_result;
18911da177e4SLinus Torvalds 	}
1892c6a44287SMartin K. Petersen 
18936c78cc06SAkinobu Mita 	read_lock_irqsave(&atomic_rw, iflags);
18946c78cc06SAkinobu Mita 
1895c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
1896c6a44287SMartin K. Petersen 	if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
1897395cef03SMartin K. Petersen 		int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
1898c6a44287SMartin K. Petersen 
1899c6a44287SMartin K. Petersen 		if (prot_ret) {
19006c78cc06SAkinobu Mita 			read_unlock_irqrestore(&atomic_rw, iflags);
1901c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
1902c6a44287SMartin K. Petersen 			return illegal_condition_result;
1903c6a44287SMartin K. Petersen 		}
1904c6a44287SMartin K. Petersen 	}
1905c6a44287SMartin K. Petersen 
190619789100SFUJITA Tomonori 	ret = do_device_access(SCpnt, devip, lba, num, 0);
19071da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
1908a4517511SAkinobu Mita 	if (ret == -1)
1909a4517511SAkinobu Mita 		return DID_ERROR << 16;
1910a4517511SAkinobu Mita 
1911a4517511SAkinobu Mita 	scsi_in(SCpnt)->resid = scsi_bufflen(SCpnt) - ret;
1912a4517511SAkinobu Mita 
1913a4517511SAkinobu Mita 	return 0;
19141da177e4SLinus Torvalds }
19151da177e4SLinus Torvalds 
1916c6a44287SMartin K. Petersen void dump_sector(unsigned char *buf, int len)
1917c6a44287SMartin K. Petersen {
1918c6a44287SMartin K. Petersen 	int i, j;
1919c6a44287SMartin K. Petersen 
1920c6a44287SMartin K. Petersen 	printk(KERN_ERR ">>> Sector Dump <<<\n");
1921c6a44287SMartin K. Petersen 
1922c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
1923c6a44287SMartin K. Petersen 		printk(KERN_ERR "%04d: ", i);
1924c6a44287SMartin K. Petersen 
1925c6a44287SMartin K. Petersen 		for (j = 0 ; j < 16 ; j++) {
1926c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
1927c6a44287SMartin K. Petersen 			if (c >= 0x20 && c < 0x7e)
1928c6a44287SMartin K. Petersen 				printk(" %c ", buf[i+j]);
1929c6a44287SMartin K. Petersen 			else
1930c6a44287SMartin K. Petersen 				printk("%02x ", buf[i+j]);
1931c6a44287SMartin K. Petersen 		}
1932c6a44287SMartin K. Petersen 
1933c6a44287SMartin K. Petersen 		printk("\n");
1934c6a44287SMartin K. Petersen 	}
1935c6a44287SMartin K. Petersen }
1936c6a44287SMartin K. Petersen 
1937c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
1938395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
1939c6a44287SMartin K. Petersen {
1940be4e11beSAkinobu Mita 	int ret;
1941c6a44287SMartin K. Petersen 	struct sd_dif_tuple *sdt;
1942be4e11beSAkinobu Mita 	void *daddr;
194365f72f2aSAkinobu Mita 	sector_t sector = start_sec;
1944c6a44287SMartin K. Petersen 	int ppage_offset;
1945be4e11beSAkinobu Mita 	int dpage_offset;
1946be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
1947be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
1948c6a44287SMartin K. Petersen 
1949c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
1950c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
1951c6a44287SMartin K. Petersen 
1952be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
1953be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
1954be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
1955be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
1956be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
1957c6a44287SMartin K. Petersen 
1958be4e11beSAkinobu Mita 	/* For each protection page */
1959be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
1960be4e11beSAkinobu Mita 		dpage_offset = 0;
1961be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
1962be4e11beSAkinobu Mita 			ret = 0x01;
1963be4e11beSAkinobu Mita 			goto out;
1964c6a44287SMartin K. Petersen 		}
1965c6a44287SMartin K. Petersen 
1966be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
1967be4e11beSAkinobu Mita 		     ppage_offset += sizeof(struct sd_dif_tuple)) {
1968be4e11beSAkinobu Mita 			/* If we're at the end of the current
1969be4e11beSAkinobu Mita 			 * data page advance to the next one
1970be4e11beSAkinobu Mita 			 */
1971be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
1972be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
1973be4e11beSAkinobu Mita 					ret = 0x01;
1974be4e11beSAkinobu Mita 					goto out;
1975be4e11beSAkinobu Mita 				}
1976be4e11beSAkinobu Mita 				dpage_offset = 0;
1977be4e11beSAkinobu Mita 			}
1978c6a44287SMartin K. Petersen 
1979be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
1980be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
1981be4e11beSAkinobu Mita 
1982be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
1983beb40ea4SAkinobu Mita 			if (ret) {
1984be4e11beSAkinobu Mita 				dump_sector(daddr, scsi_debug_sector_size);
1985395cef03SMartin K. Petersen 				goto out;
1986395cef03SMartin K. Petersen 			}
1987395cef03SMartin K. Petersen 
1988c6a44287SMartin K. Petersen 			sector++;
1989395cef03SMartin K. Petersen 			ei_lba++;
1990be4e11beSAkinobu Mita 			dpage_offset += scsi_debug_sector_size;
1991c6a44287SMartin K. Petersen 		}
1992be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
1993be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
1994c6a44287SMartin K. Petersen 	}
1995be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
1996c6a44287SMartin K. Petersen 
199765f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
1998c6a44287SMartin K. Petersen 	dix_writes++;
1999c6a44287SMartin K. Petersen 
2000c6a44287SMartin K. Petersen 	return 0;
2001c6a44287SMartin K. Petersen 
2002c6a44287SMartin K. Petersen out:
2003c6a44287SMartin K. Petersen 	dif_errors++;
2004be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
2005be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2006c6a44287SMartin K. Petersen 	return ret;
2007c6a44287SMartin K. Petersen }
2008c6a44287SMartin K. Petersen 
2009b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
2010b90ebc3dSAkinobu Mita {
2011b90ebc3dSAkinobu Mita 	if (scsi_debug_unmap_alignment) {
2012b90ebc3dSAkinobu Mita 		lba += scsi_debug_unmap_granularity -
2013b90ebc3dSAkinobu Mita 			scsi_debug_unmap_alignment;
2014b90ebc3dSAkinobu Mita 	}
2015b90ebc3dSAkinobu Mita 	do_div(lba, scsi_debug_unmap_granularity);
2016b90ebc3dSAkinobu Mita 
2017b90ebc3dSAkinobu Mita 	return lba;
2018b90ebc3dSAkinobu Mita }
2019b90ebc3dSAkinobu Mita 
2020b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
2021b90ebc3dSAkinobu Mita {
2022a027b5b9SAkinobu Mita 	sector_t lba = index * scsi_debug_unmap_granularity;
2023a027b5b9SAkinobu Mita 
2024a027b5b9SAkinobu Mita 	if (scsi_debug_unmap_alignment) {
2025a027b5b9SAkinobu Mita 		lba -= scsi_debug_unmap_granularity -
2026b90ebc3dSAkinobu Mita 			scsi_debug_unmap_alignment;
2027b90ebc3dSAkinobu Mita 	}
2028b90ebc3dSAkinobu Mita 
2029a027b5b9SAkinobu Mita 	return lba;
2030a027b5b9SAkinobu Mita }
2031a027b5b9SAkinobu Mita 
203244d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
203344d92694SMartin K. Petersen {
2034b90ebc3dSAkinobu Mita 	sector_t end;
2035b90ebc3dSAkinobu Mita 	unsigned int mapped;
2036b90ebc3dSAkinobu Mita 	unsigned long index;
2037b90ebc3dSAkinobu Mita 	unsigned long next;
203844d92694SMartin K. Petersen 
2039b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
2040b90ebc3dSAkinobu Mita 	mapped = test_bit(index, map_storep);
204144d92694SMartin K. Petersen 
204244d92694SMartin K. Petersen 	if (mapped)
2043b90ebc3dSAkinobu Mita 		next = find_next_zero_bit(map_storep, map_size, index);
204444d92694SMartin K. Petersen 	else
2045b90ebc3dSAkinobu Mita 		next = find_next_bit(map_storep, map_size, index);
204644d92694SMartin K. Petersen 
2047b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
204844d92694SMartin K. Petersen 	*num = end - lba;
204944d92694SMartin K. Petersen 
205044d92694SMartin K. Petersen 	return mapped;
205144d92694SMartin K. Petersen }
205244d92694SMartin K. Petersen 
205344d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
205444d92694SMartin K. Petersen {
205544d92694SMartin K. Petersen 	sector_t end = lba + len;
205644d92694SMartin K. Petersen 
205744d92694SMartin K. Petersen 	while (lba < end) {
2058b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
205944d92694SMartin K. Petersen 
2060b90ebc3dSAkinobu Mita 		if (index < map_size)
2061b90ebc3dSAkinobu Mita 			set_bit(index, map_storep);
206244d92694SMartin K. Petersen 
2063b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
206444d92694SMartin K. Petersen 	}
206544d92694SMartin K. Petersen }
206644d92694SMartin K. Petersen 
206744d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
206844d92694SMartin K. Petersen {
206944d92694SMartin K. Petersen 	sector_t end = lba + len;
207044d92694SMartin K. Petersen 
207144d92694SMartin K. Petersen 	while (lba < end) {
2072b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
207344d92694SMartin K. Petersen 
2074b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
2075b90ebc3dSAkinobu Mita 		    lba + scsi_debug_unmap_granularity <= end &&
2076b90ebc3dSAkinobu Mita 		    index < map_size) {
2077b90ebc3dSAkinobu Mita 			clear_bit(index, map_storep);
2078b90ebc3dSAkinobu Mita 			if (scsi_debug_lbprz) {
2079be1dd78dSEric Sandeen 				memset(fake_storep +
2080cc34a8e6SAkinobu Mita 				       lba * scsi_debug_sector_size, 0,
2081cc34a8e6SAkinobu Mita 				       scsi_debug_sector_size *
2082cc34a8e6SAkinobu Mita 				       scsi_debug_unmap_granularity);
2083be1dd78dSEric Sandeen 			}
2084e9926b43SAkinobu Mita 			if (dif_storep) {
2085e9926b43SAkinobu Mita 				memset(dif_storep + lba, 0xff,
2086e9926b43SAkinobu Mita 				       sizeof(*dif_storep) *
2087e9926b43SAkinobu Mita 				       scsi_debug_unmap_granularity);
2088e9926b43SAkinobu Mita 			}
2089b90ebc3dSAkinobu Mita 		}
2090b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
209144d92694SMartin K. Petersen 	}
209244d92694SMartin K. Petersen }
209344d92694SMartin K. Petersen 
2094c65b1445SDouglas Gilbert static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
2095395cef03SMartin K. Petersen 		      unsigned int num, struct sdebug_dev_info *devip,
2096395cef03SMartin K. Petersen 		      u32 ei_lba)
20971da177e4SLinus Torvalds {
20981da177e4SLinus Torvalds 	unsigned long iflags;
209919789100SFUJITA Tomonori 	int ret;
21001da177e4SLinus Torvalds 
210119789100SFUJITA Tomonori 	ret = check_device_access_params(devip, lba, num);
210219789100SFUJITA Tomonori 	if (ret)
210319789100SFUJITA Tomonori 		return ret;
21041da177e4SLinus Torvalds 
21056c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
21066c78cc06SAkinobu Mita 
2107c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2108c6a44287SMartin K. Petersen 	if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
2109395cef03SMartin K. Petersen 		int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
2110c6a44287SMartin K. Petersen 
2111c6a44287SMartin K. Petersen 		if (prot_ret) {
21126c78cc06SAkinobu Mita 			write_unlock_irqrestore(&atomic_rw, iflags);
2113c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
2114c6a44287SMartin K. Petersen 			return illegal_condition_result;
2115c6a44287SMartin K. Petersen 		}
2116c6a44287SMartin K. Petersen 	}
2117c6a44287SMartin K. Petersen 
211819789100SFUJITA Tomonori 	ret = do_device_access(SCpnt, devip, lba, num, 1);
21199ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
212044d92694SMartin K. Petersen 		map_region(lba, num);
21211da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
212219789100SFUJITA Tomonori 	if (-1 == ret)
21231da177e4SLinus Torvalds 		return (DID_ERROR << 16);
2124597136abSMartin K. Petersen 	else if ((ret < (num * scsi_debug_sector_size)) &&
21251da177e4SLinus Torvalds 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
2126c65b1445SDouglas Gilbert 		printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
2127597136abSMartin K. Petersen 		       " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
212844d92694SMartin K. Petersen 
21291da177e4SLinus Torvalds 	return 0;
21301da177e4SLinus Torvalds }
21311da177e4SLinus Torvalds 
213244d92694SMartin K. Petersen static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,
213344d92694SMartin K. Petersen 		      unsigned int num, struct sdebug_dev_info *devip,
213444d92694SMartin K. Petersen 			   u32 ei_lba, unsigned int unmap)
213544d92694SMartin K. Petersen {
213644d92694SMartin K. Petersen 	unsigned long iflags;
213744d92694SMartin K. Petersen 	unsigned long long i;
213844d92694SMartin K. Petersen 	int ret;
213944d92694SMartin K. Petersen 
214044d92694SMartin K. Petersen 	ret = check_device_access_params(devip, lba, num);
214144d92694SMartin K. Petersen 	if (ret)
214244d92694SMartin K. Petersen 		return ret;
214344d92694SMartin K. Petersen 
21445b94e232SMartin K. Petersen 	if (num > scsi_debug_write_same_length) {
21455b94e232SMartin K. Petersen 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
21465b94e232SMartin K. Petersen 				0);
21475b94e232SMartin K. Petersen 		return check_condition_result;
21485b94e232SMartin K. Petersen 	}
21495b94e232SMartin K. Petersen 
215044d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
215144d92694SMartin K. Petersen 
21529ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
215344d92694SMartin K. Petersen 		unmap_region(lba, num);
215444d92694SMartin K. Petersen 		goto out;
215544d92694SMartin K. Petersen 	}
215644d92694SMartin K. Petersen 
215744d92694SMartin K. Petersen 	/* Else fetch one logical block */
215844d92694SMartin K. Petersen 	ret = fetch_to_dev_buffer(scmd,
215944d92694SMartin K. Petersen 				  fake_storep + (lba * scsi_debug_sector_size),
216044d92694SMartin K. Petersen 				  scsi_debug_sector_size);
216144d92694SMartin K. Petersen 
216244d92694SMartin K. Petersen 	if (-1 == ret) {
216344d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
216444d92694SMartin K. Petersen 		return (DID_ERROR << 16);
216544d92694SMartin K. Petersen 	} else if ((ret < (num * scsi_debug_sector_size)) &&
216644d92694SMartin K. Petersen 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
216744d92694SMartin K. Petersen 		printk(KERN_INFO "scsi_debug: write same: cdb indicated=%u, "
216844d92694SMartin K. Petersen 		       " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
216944d92694SMartin K. Petersen 
217044d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
217144d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
217244d92694SMartin K. Petersen 		memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size),
217344d92694SMartin K. Petersen 		       fake_storep + (lba * scsi_debug_sector_size),
217444d92694SMartin K. Petersen 		       scsi_debug_sector_size);
217544d92694SMartin K. Petersen 
21769ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
217744d92694SMartin K. Petersen 		map_region(lba, num);
217844d92694SMartin K. Petersen out:
217944d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
218044d92694SMartin K. Petersen 
218144d92694SMartin K. Petersen 	return 0;
218244d92694SMartin K. Petersen }
218344d92694SMartin K. Petersen 
218444d92694SMartin K. Petersen struct unmap_block_desc {
218544d92694SMartin K. Petersen 	__be64	lba;
218644d92694SMartin K. Petersen 	__be32	blocks;
218744d92694SMartin K. Petersen 	__be32	__reserved;
218844d92694SMartin K. Petersen };
218944d92694SMartin K. Petersen 
219044d92694SMartin K. Petersen static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
219144d92694SMartin K. Petersen {
219244d92694SMartin K. Petersen 	unsigned char *buf;
219344d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
219444d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
219544d92694SMartin K. Petersen 	int ret;
21966c78cc06SAkinobu Mita 	unsigned long iflags;
219744d92694SMartin K. Petersen 
219844d92694SMartin K. Petersen 	ret = check_readiness(scmd, 1, devip);
219944d92694SMartin K. Petersen 	if (ret)
220044d92694SMartin K. Petersen 		return ret;
220144d92694SMartin K. Petersen 
220244d92694SMartin K. Petersen 	payload_len = get_unaligned_be16(&scmd->cmnd[7]);
220344d92694SMartin K. Petersen 	BUG_ON(scsi_bufflen(scmd) != payload_len);
220444d92694SMartin K. Petersen 
220544d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
220644d92694SMartin K. Petersen 
220744d92694SMartin K. Petersen 	buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC);
220844d92694SMartin K. Petersen 	if (!buf)
220944d92694SMartin K. Petersen 		return check_condition_result;
221044d92694SMartin K. Petersen 
221144d92694SMartin K. Petersen 	scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
221244d92694SMartin K. Petersen 
221344d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
221444d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
221544d92694SMartin K. Petersen 
221644d92694SMartin K. Petersen 	desc = (void *)&buf[8];
221744d92694SMartin K. Petersen 
22186c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
22196c78cc06SAkinobu Mita 
222044d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
222144d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
222244d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
222344d92694SMartin K. Petersen 
222444d92694SMartin K. Petersen 		ret = check_device_access_params(devip, lba, num);
222544d92694SMartin K. Petersen 		if (ret)
222644d92694SMartin K. Petersen 			goto out;
222744d92694SMartin K. Petersen 
222844d92694SMartin K. Petersen 		unmap_region(lba, num);
222944d92694SMartin K. Petersen 	}
223044d92694SMartin K. Petersen 
223144d92694SMartin K. Petersen 	ret = 0;
223244d92694SMartin K. Petersen 
223344d92694SMartin K. Petersen out:
22346c78cc06SAkinobu Mita 	write_unlock_irqrestore(&atomic_rw, iflags);
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 {
2335be4e11beSAkinobu Mita 	int j;
2336c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
2337c639d14eSFUJITA Tomonori 	unsigned int offset;
2338c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
2339be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
2340c639d14eSFUJITA Tomonori 
2341c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
2342c639d14eSFUJITA Tomonori 	buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
2343c5af0db9SAkinobu Mita 	if (!buf) {
2344c5af0db9SAkinobu Mita 		mk_sense_buffer(devip, NOT_READY,
2345c5af0db9SAkinobu Mita 				LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
2346c5af0db9SAkinobu Mita 		return check_condition_result;
2347c5af0db9SAkinobu Mita 	}
2348c639d14eSFUJITA Tomonori 
234921a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
2350c639d14eSFUJITA Tomonori 
2351c639d14eSFUJITA Tomonori 	offset = 0;
2352be4e11beSAkinobu Mita 	sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
2353be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_TO_SG);
2354c639d14eSFUJITA Tomonori 
2355be4e11beSAkinobu Mita 	while (sg_miter_next(&miter)) {
2356be4e11beSAkinobu Mita 		kaddr = miter.addr;
2357be4e11beSAkinobu Mita 		for (j = 0; j < miter.length; j++)
2358be4e11beSAkinobu Mita 			*(kaddr + j) ^= *(buf + offset + j);
2359c639d14eSFUJITA Tomonori 
2360be4e11beSAkinobu Mita 		offset += miter.length;
2361c639d14eSFUJITA Tomonori 	}
2362be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
2363c639d14eSFUJITA Tomonori 	kfree(buf);
2364c639d14eSFUJITA Tomonori 
2365be4e11beSAkinobu Mita 	return 0;
2366c639d14eSFUJITA Tomonori }
2367c639d14eSFUJITA Tomonori 
23681da177e4SLinus Torvalds /* When timer goes off this function is called. */
23691da177e4SLinus Torvalds static void timer_intr_handler(unsigned long indx)
23701da177e4SLinus Torvalds {
23711da177e4SLinus Torvalds 	struct sdebug_queued_cmd * sqcp;
23721da177e4SLinus Torvalds 	unsigned long iflags;
23731da177e4SLinus Torvalds 
237478d4e5a0SDouglas Gilbert 	if (indx >= scsi_debug_max_queue) {
23751da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
23761da177e4SLinus Torvalds 		       "large\n");
23771da177e4SLinus Torvalds 		return;
23781da177e4SLinus Torvalds 	}
23791da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
23801da177e4SLinus Torvalds 	sqcp = &queued_arr[(int)indx];
23811da177e4SLinus Torvalds 	if (! sqcp->in_use) {
23821da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
23831da177e4SLinus Torvalds 		       "interrupt\n");
23841da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
23851da177e4SLinus Torvalds 		return;
23861da177e4SLinus Torvalds 	}
23871da177e4SLinus Torvalds 	sqcp->in_use = 0;
23881da177e4SLinus Torvalds 	if (sqcp->done_funct) {
23891da177e4SLinus Torvalds 		sqcp->a_cmnd->result = sqcp->scsi_result;
23901da177e4SLinus Torvalds 		sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
23911da177e4SLinus Torvalds 	}
23921da177e4SLinus Torvalds 	sqcp->done_funct = NULL;
23931da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
23941da177e4SLinus Torvalds }
23951da177e4SLinus Torvalds 
23961da177e4SLinus Torvalds 
23978dea0d02SFUJITA Tomonori static struct sdebug_dev_info *
23988dea0d02SFUJITA Tomonori sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
23995cb2fc06SFUJITA Tomonori {
24005cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
24015cb2fc06SFUJITA Tomonori 
24025cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
24035cb2fc06SFUJITA Tomonori 	if (devip) {
24045cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
24055cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
24065cb2fc06SFUJITA Tomonori 	}
24075cb2fc06SFUJITA Tomonori 	return devip;
24085cb2fc06SFUJITA Tomonori }
24095cb2fc06SFUJITA Tomonori 
24101da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
24111da177e4SLinus Torvalds {
24121da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
24131da177e4SLinus Torvalds 	struct sdebug_dev_info * open_devip = NULL;
24141da177e4SLinus Torvalds 	struct sdebug_dev_info * devip =
24151da177e4SLinus Torvalds 			(struct sdebug_dev_info *)sdev->hostdata;
24161da177e4SLinus Torvalds 
24171da177e4SLinus Torvalds 	if (devip)
24181da177e4SLinus Torvalds 		return devip;
2419d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
24201da177e4SLinus Torvalds 	if (!sdbg_host) {
24211da177e4SLinus Torvalds                 printk(KERN_ERR "Host info NULL\n");
24221da177e4SLinus Torvalds 		return NULL;
24231da177e4SLinus Torvalds         }
24241da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
24251da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
24261da177e4SLinus Torvalds                     (devip->target == sdev->id) &&
24271da177e4SLinus Torvalds                     (devip->lun == sdev->lun))
24281da177e4SLinus Torvalds                         return devip;
24291da177e4SLinus Torvalds 		else {
24301da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
24311da177e4SLinus Torvalds 				open_devip = devip;
24321da177e4SLinus Torvalds 		}
24331da177e4SLinus Torvalds 	}
24345cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
24355cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
24365cb2fc06SFUJITA Tomonori 		if (!open_devip) {
24371da177e4SLinus Torvalds 			printk(KERN_ERR "%s: out of memory at line %d\n",
2438cadbd4a5SHarvey Harrison 				__func__, __LINE__);
24391da177e4SLinus Torvalds 			return NULL;
24401da177e4SLinus Torvalds 		}
24411da177e4SLinus Torvalds 	}
2442a75869d1SFUJITA Tomonori 
24431da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
24441da177e4SLinus Torvalds 	open_devip->target = sdev->id;
24451da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
24461da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
24471da177e4SLinus Torvalds 	open_devip->reset = 1;
24481da177e4SLinus Torvalds 	open_devip->used = 1;
24491da177e4SLinus Torvalds 	memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
24501da177e4SLinus Torvalds 	if (scsi_debug_dsense)
24511da177e4SLinus Torvalds 		open_devip->sense_buff[0] = 0x72;
24521da177e4SLinus Torvalds 	else {
24531da177e4SLinus Torvalds 		open_devip->sense_buff[0] = 0x70;
24541da177e4SLinus Torvalds 		open_devip->sense_buff[7] = 0xa;
24551da177e4SLinus Torvalds 	}
2456c65b1445SDouglas Gilbert 	if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2457c65b1445SDouglas Gilbert 		open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
2458a75869d1SFUJITA Tomonori 
24591da177e4SLinus Torvalds 	return open_devip;
24601da177e4SLinus Torvalds }
24611da177e4SLinus Torvalds 
24628dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
24631da177e4SLinus Torvalds {
24648dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
24658dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
24668dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
246775ad23bcSNick Piggin 	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
24688dea0d02SFUJITA Tomonori 	return 0;
24698dea0d02SFUJITA Tomonori }
24701da177e4SLinus Torvalds 
24718dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
24728dea0d02SFUJITA Tomonori {
24738dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip;
2474a34c4e98SFUJITA Tomonori 
24751da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
24768dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
24778dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
24788dea0d02SFUJITA Tomonori 	if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
24798dea0d02SFUJITA Tomonori 		sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
24808dea0d02SFUJITA Tomonori 	devip = devInfoReg(sdp);
24818dea0d02SFUJITA Tomonori 	if (NULL == devip)
24828dea0d02SFUJITA Tomonori 		return 1;	/* no resources, will be marked offline */
24838dea0d02SFUJITA Tomonori 	sdp->hostdata = devip;
24848dea0d02SFUJITA Tomonori 	if (sdp->host->cmd_per_lun)
24858dea0d02SFUJITA Tomonori 		scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
24868dea0d02SFUJITA Tomonori 					sdp->host->cmd_per_lun);
24876bb5e6e7SAkinobu Mita 	blk_queue_max_segment_size(sdp->request_queue, -1U);
248878d4e5a0SDouglas Gilbert 	if (scsi_debug_no_uld)
248978d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
24908dea0d02SFUJITA Tomonori 	return 0;
24918dea0d02SFUJITA Tomonori }
24928dea0d02SFUJITA Tomonori 
24938dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
24948dea0d02SFUJITA Tomonori {
24958dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
24968dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
24978dea0d02SFUJITA Tomonori 
24988dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
24998dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
25008dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
25018dea0d02SFUJITA Tomonori 	if (devip) {
250225985edcSLucas De Marchi 		/* make this slot available for re-use */
25038dea0d02SFUJITA Tomonori 		devip->used = 0;
25048dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
25058dea0d02SFUJITA Tomonori 	}
25068dea0d02SFUJITA Tomonori }
25078dea0d02SFUJITA Tomonori 
25088dea0d02SFUJITA Tomonori /* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
25098dea0d02SFUJITA Tomonori static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
25108dea0d02SFUJITA Tomonori {
25118dea0d02SFUJITA Tomonori 	unsigned long iflags;
25128dea0d02SFUJITA Tomonori 	int k;
25138dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
25148dea0d02SFUJITA Tomonori 
25158dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
251678d4e5a0SDouglas Gilbert 	for (k = 0; k < scsi_debug_max_queue; ++k) {
25178dea0d02SFUJITA Tomonori 		sqcp = &queued_arr[k];
25188dea0d02SFUJITA Tomonori 		if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
25198dea0d02SFUJITA Tomonori 			del_timer_sync(&sqcp->cmnd_timer);
25208dea0d02SFUJITA Tomonori 			sqcp->in_use = 0;
25218dea0d02SFUJITA Tomonori 			sqcp->a_cmnd = NULL;
25228dea0d02SFUJITA Tomonori 			break;
25238dea0d02SFUJITA Tomonori 		}
25248dea0d02SFUJITA Tomonori 	}
25258dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
252678d4e5a0SDouglas Gilbert 	return (k < scsi_debug_max_queue) ? 1 : 0;
25278dea0d02SFUJITA Tomonori }
25288dea0d02SFUJITA Tomonori 
25298dea0d02SFUJITA Tomonori /* Deletes (stops) timers of all queued commands */
25308dea0d02SFUJITA Tomonori static void stop_all_queued(void)
25318dea0d02SFUJITA Tomonori {
25328dea0d02SFUJITA Tomonori 	unsigned long iflags;
25338dea0d02SFUJITA Tomonori 	int k;
25348dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
25358dea0d02SFUJITA Tomonori 
25368dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
253778d4e5a0SDouglas Gilbert 	for (k = 0; k < scsi_debug_max_queue; ++k) {
25388dea0d02SFUJITA Tomonori 		sqcp = &queued_arr[k];
25398dea0d02SFUJITA Tomonori 		if (sqcp->in_use && sqcp->a_cmnd) {
25408dea0d02SFUJITA Tomonori 			del_timer_sync(&sqcp->cmnd_timer);
25418dea0d02SFUJITA Tomonori 			sqcp->in_use = 0;
25428dea0d02SFUJITA Tomonori 			sqcp->a_cmnd = NULL;
25438dea0d02SFUJITA Tomonori 		}
25448dea0d02SFUJITA Tomonori 	}
25458dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
25461da177e4SLinus Torvalds }
25471da177e4SLinus Torvalds 
25481da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
25491da177e4SLinus Torvalds {
25501da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25511da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: abort\n");
25521da177e4SLinus Torvalds 	++num_aborts;
25531da177e4SLinus Torvalds 	stop_queued_cmnd(SCpnt);
25541da177e4SLinus Torvalds 	return SUCCESS;
25551da177e4SLinus Torvalds }
25561da177e4SLinus Torvalds 
25571da177e4SLinus Torvalds static int scsi_debug_biosparam(struct scsi_device *sdev,
25581da177e4SLinus Torvalds 		struct block_device * bdev, sector_t capacity, int *info)
25591da177e4SLinus Torvalds {
25601da177e4SLinus Torvalds 	int res;
25611da177e4SLinus Torvalds 	unsigned char *buf;
25621da177e4SLinus Torvalds 
25631da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25641da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: biosparam\n");
25651da177e4SLinus Torvalds 	buf = scsi_bios_ptable(bdev);
25661da177e4SLinus Torvalds 	if (buf) {
25671da177e4SLinus Torvalds 		res = scsi_partsize(buf, capacity,
25681da177e4SLinus Torvalds 				    &info[2], &info[0], &info[1]);
25691da177e4SLinus Torvalds 		kfree(buf);
25701da177e4SLinus Torvalds 		if (! res)
25711da177e4SLinus Torvalds 			return res;
25721da177e4SLinus Torvalds 	}
25731da177e4SLinus Torvalds 	info[0] = sdebug_heads;
25741da177e4SLinus Torvalds 	info[1] = sdebug_sectors_per;
25751da177e4SLinus Torvalds 	info[2] = sdebug_cylinders_per;
25761da177e4SLinus Torvalds 	return 0;
25771da177e4SLinus Torvalds }
25781da177e4SLinus Torvalds 
25791da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
25801da177e4SLinus Torvalds {
25811da177e4SLinus Torvalds 	struct sdebug_dev_info * devip;
25821da177e4SLinus Torvalds 
25831da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25841da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: device_reset\n");
25851da177e4SLinus Torvalds 	++num_dev_resets;
25861da177e4SLinus Torvalds 	if (SCpnt) {
25871da177e4SLinus Torvalds 		devip = devInfoReg(SCpnt->device);
25881da177e4SLinus Torvalds 		if (devip)
25891da177e4SLinus Torvalds 			devip->reset = 1;
25901da177e4SLinus Torvalds 	}
25911da177e4SLinus Torvalds 	return SUCCESS;
25921da177e4SLinus Torvalds }
25931da177e4SLinus Torvalds 
25941da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
25951da177e4SLinus Torvalds {
25961da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
25971da177e4SLinus Torvalds         struct sdebug_dev_info * dev_info;
25981da177e4SLinus Torvalds         struct scsi_device * sdp;
25991da177e4SLinus Torvalds         struct Scsi_Host * hp;
26001da177e4SLinus Torvalds 
26011da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
26021da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: bus_reset\n");
26031da177e4SLinus Torvalds 	++num_bus_resets;
26041da177e4SLinus Torvalds 	if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
2605d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
26061da177e4SLinus Torvalds 		if (sdbg_host) {
26071da177e4SLinus Torvalds 			list_for_each_entry(dev_info,
26081da177e4SLinus Torvalds                                             &sdbg_host->dev_info_list,
26091da177e4SLinus Torvalds                                             dev_list)
26101da177e4SLinus Torvalds 				dev_info->reset = 1;
26111da177e4SLinus Torvalds 		}
26121da177e4SLinus Torvalds 	}
26131da177e4SLinus Torvalds 	return SUCCESS;
26141da177e4SLinus Torvalds }
26151da177e4SLinus Torvalds 
26161da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
26171da177e4SLinus Torvalds {
26181da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
26191da177e4SLinus Torvalds         struct sdebug_dev_info * dev_info;
26201da177e4SLinus Torvalds 
26211da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
26221da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: host_reset\n");
26231da177e4SLinus Torvalds 	++num_host_resets;
26241da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
26251da177e4SLinus Torvalds         list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
26261da177e4SLinus Torvalds                 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
26271da177e4SLinus Torvalds                                     dev_list)
26281da177e4SLinus Torvalds                         dev_info->reset = 1;
26291da177e4SLinus Torvalds         }
26301da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
26311da177e4SLinus Torvalds 	stop_all_queued();
26321da177e4SLinus Torvalds 	return SUCCESS;
26331da177e4SLinus Torvalds }
26341da177e4SLinus Torvalds 
26351da177e4SLinus Torvalds /* Initializes timers in queued array */
26361da177e4SLinus Torvalds static void __init init_all_queued(void)
26371da177e4SLinus Torvalds {
26381da177e4SLinus Torvalds 	unsigned long iflags;
26391da177e4SLinus Torvalds 	int k;
26401da177e4SLinus Torvalds 	struct sdebug_queued_cmd * sqcp;
26411da177e4SLinus Torvalds 
26421da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
264378d4e5a0SDouglas Gilbert 	for (k = 0; k < scsi_debug_max_queue; ++k) {
26441da177e4SLinus Torvalds 		sqcp = &queued_arr[k];
26451da177e4SLinus Torvalds 		init_timer(&sqcp->cmnd_timer);
26461da177e4SLinus Torvalds 		sqcp->in_use = 0;
26471da177e4SLinus Torvalds 		sqcp->a_cmnd = NULL;
26481da177e4SLinus Torvalds 	}
26491da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
26501da177e4SLinus Torvalds }
26511da177e4SLinus Torvalds 
2652f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
26535f2578e5SFUJITA Tomonori 				      unsigned long store_size)
26541da177e4SLinus Torvalds {
26551da177e4SLinus Torvalds 	struct partition * pp;
26561da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
26571da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
26581da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
26591da177e4SLinus Torvalds 
26601da177e4SLinus Torvalds 	/* assume partition table already zeroed */
2661f58b0efbSFUJITA Tomonori 	if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
26621da177e4SLinus Torvalds 		return;
26631da177e4SLinus Torvalds 	if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
26641da177e4SLinus Torvalds 		scsi_debug_num_parts = SDEBUG_MAX_PARTS;
26651da177e4SLinus Torvalds 		printk(KERN_WARNING "scsi_debug:build_parts: reducing "
26661da177e4SLinus Torvalds 				    "partitions to %d\n", SDEBUG_MAX_PARTS);
26671da177e4SLinus Torvalds 	}
2668c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
26691da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
26701da177e4SLinus Torvalds 			   / scsi_debug_num_parts;
26711da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
26721da177e4SLinus Torvalds         starts[0] = sdebug_sectors_per;
26731da177e4SLinus Torvalds 	for (k = 1; k < scsi_debug_num_parts; ++k)
26741da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
26751da177e4SLinus Torvalds 			    * heads_by_sects;
26761da177e4SLinus Torvalds 	starts[scsi_debug_num_parts] = num_sectors;
26771da177e4SLinus Torvalds 	starts[scsi_debug_num_parts + 1] = 0;
26781da177e4SLinus Torvalds 
26791da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
26801da177e4SLinus Torvalds 	ramp[511] = 0xAA;
26811da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
26821da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
26831da177e4SLinus Torvalds 		start_sec = starts[k];
26841da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
26851da177e4SLinus Torvalds 		pp->boot_ind = 0;
26861da177e4SLinus Torvalds 
26871da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
26881da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
26891da177e4SLinus Torvalds 			   / sdebug_sectors_per;
26901da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
26911da177e4SLinus Torvalds 
26921da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
26931da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
26941da177e4SLinus Torvalds 			       / sdebug_sectors_per;
26951da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
26961da177e4SLinus Torvalds 
2697150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
2698150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
26991da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
27001da177e4SLinus Torvalds 	}
27011da177e4SLinus Torvalds }
27021da177e4SLinus Torvalds 
27031da177e4SLinus Torvalds static int schedule_resp(struct scsi_cmnd * cmnd,
27041da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip,
27051da177e4SLinus Torvalds 			 done_funct_t done, int scsi_result, int delta_jiff)
27061da177e4SLinus Torvalds {
27071da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
27081da177e4SLinus Torvalds 		if (scsi_result) {
27091da177e4SLinus Torvalds 			struct scsi_device * sdp = cmnd->device;
27101da177e4SLinus Torvalds 
2711c65b1445SDouglas Gilbert 			printk(KERN_INFO "scsi_debug:    <%u %u %u %u> "
2712c65b1445SDouglas Gilbert 			       "non-zero result=0x%x\n", sdp->host->host_no,
2713c65b1445SDouglas Gilbert 			       sdp->channel, sdp->id, sdp->lun, scsi_result);
27141da177e4SLinus Torvalds 		}
27151da177e4SLinus Torvalds 	}
27161da177e4SLinus Torvalds 	if (cmnd && devip) {
27171da177e4SLinus Torvalds 		/* simulate autosense by this driver */
27181da177e4SLinus Torvalds 		if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
27191da177e4SLinus Torvalds 			memcpy(cmnd->sense_buffer, devip->sense_buff,
27201da177e4SLinus Torvalds 			       (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
27211da177e4SLinus Torvalds 			       SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
27221da177e4SLinus Torvalds 	}
27231da177e4SLinus Torvalds 	if (delta_jiff <= 0) {
27241da177e4SLinus Torvalds 		if (cmnd)
27251da177e4SLinus Torvalds 			cmnd->result = scsi_result;
27261da177e4SLinus Torvalds 		if (done)
27271da177e4SLinus Torvalds 			done(cmnd);
27281da177e4SLinus Torvalds 		return 0;
27291da177e4SLinus Torvalds 	} else {
27301da177e4SLinus Torvalds 		unsigned long iflags;
27311da177e4SLinus Torvalds 		int k;
27321da177e4SLinus Torvalds 		struct sdebug_queued_cmd * sqcp = NULL;
27331da177e4SLinus Torvalds 
27341da177e4SLinus Torvalds 		spin_lock_irqsave(&queued_arr_lock, iflags);
273578d4e5a0SDouglas Gilbert 		for (k = 0; k < scsi_debug_max_queue; ++k) {
27361da177e4SLinus Torvalds 			sqcp = &queued_arr[k];
27371da177e4SLinus Torvalds 			if (! sqcp->in_use)
27381da177e4SLinus Torvalds 				break;
27391da177e4SLinus Torvalds 		}
274078d4e5a0SDouglas Gilbert 		if (k >= scsi_debug_max_queue) {
27411da177e4SLinus Torvalds 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
27421da177e4SLinus Torvalds 			printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
27431da177e4SLinus Torvalds 			return 1;	/* report busy to mid level */
27441da177e4SLinus Torvalds 		}
27451da177e4SLinus Torvalds 		sqcp->in_use = 1;
27461da177e4SLinus Torvalds 		sqcp->a_cmnd = cmnd;
27471da177e4SLinus Torvalds 		sqcp->scsi_result = scsi_result;
27481da177e4SLinus Torvalds 		sqcp->done_funct = done;
27491da177e4SLinus Torvalds 		sqcp->cmnd_timer.function = timer_intr_handler;
27501da177e4SLinus Torvalds 		sqcp->cmnd_timer.data = k;
27511da177e4SLinus Torvalds 		sqcp->cmnd_timer.expires = jiffies + delta_jiff;
27521da177e4SLinus Torvalds 		add_timer(&sqcp->cmnd_timer);
27531da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
27541da177e4SLinus Torvalds 		if (cmnd)
27551da177e4SLinus Torvalds 			cmnd->result = 0;
27561da177e4SLinus Torvalds 		return 0;
27571da177e4SLinus Torvalds 	}
27581da177e4SLinus Torvalds }
275923183910SDouglas Gilbert /* Note: The following macros create attribute files in the
276023183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
276123183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
276223183910SDouglas Gilbert    as it can when the corresponding attribute in the
276323183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
276423183910SDouglas Gilbert  */
2765c65b1445SDouglas Gilbert module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
27665b94e232SMartin K. Petersen module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
27670759c666SAkinobu Mita module_param_named(clustering, scsi_debug_clustering, bool, S_IRUGO | S_IWUSR);
2768c65b1445SDouglas Gilbert module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2769c65b1445SDouglas Gilbert module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
27705b94e232SMartin K. Petersen module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
27715b94e232SMartin K. Petersen module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
2772c65b1445SDouglas Gilbert module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2773c65b1445SDouglas Gilbert module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
277423183910SDouglas Gilbert module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
277568aee7baSAkinobu Mita module_param_named(guard, scsi_debug_guard, uint, S_IRUGO);
27765b94e232SMartin K. Petersen module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO);
27775b94e232SMartin K. Petersen module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO);
27785b94e232SMartin K. Petersen module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO);
2779be1dd78dSEric Sandeen module_param_named(lbprz, scsi_debug_lbprz, int, S_IRUGO);
27805b94e232SMartin K. Petersen module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
2781c65b1445SDouglas Gilbert module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
278278d4e5a0SDouglas Gilbert module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);
2783c65b1445SDouglas Gilbert module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
278478d4e5a0SDouglas Gilbert module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);
2785c65b1445SDouglas Gilbert module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2786c65b1445SDouglas Gilbert module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
27875b94e232SMartin K. Petersen module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO);
2788c65b1445SDouglas Gilbert module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
27895b94e232SMartin K. Petersen module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
2790c65b1445SDouglas Gilbert module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2791d986788bSMartin Pitt module_param_named(removable, scsi_debug_removable, bool, S_IRUGO | S_IWUSR);
2792c65b1445SDouglas Gilbert module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
27935b94e232SMartin K. Petersen module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
27945b94e232SMartin K. Petersen module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
27955b94e232SMartin K. Petersen module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
27965b94e232SMartin K. Petersen module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
27975b94e232SMartin K. Petersen module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
2798c65b1445SDouglas Gilbert module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
279923183910SDouglas Gilbert module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
280023183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
28015b94e232SMartin K. Petersen module_param_named(write_same_length, scsi_debug_write_same_length, int,
28025b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
28031da177e4SLinus Torvalds 
28041da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
28051da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
28061da177e4SLinus Torvalds MODULE_LICENSE("GPL");
28071da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION);
28081da177e4SLinus Torvalds 
28091da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
28105b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
28110759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
28121da177e4SLinus Torvalds MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
2813c65b1445SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
28145b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
28155b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
2816c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
2817beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
281823183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
28195b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
28205b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
28215b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
28225b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
2823be1dd78dSEric Sandeen MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
28245b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
2825c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
282678d4e5a0SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to 255(def))");
2827c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
282878d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
28291da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
2830c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
28315b94e232SMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
28326f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
28335b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
28341da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2835d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
28361da177e4SLinus Torvalds MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
2837ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
28385b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
28395b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
28406014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
28416014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
28425b94e232SMartin K. Petersen MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
28435b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
28445b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
28451da177e4SLinus Torvalds 
28461da177e4SLinus Torvalds static char sdebug_info[256];
28471da177e4SLinus Torvalds 
28481da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp)
28491da177e4SLinus Torvalds {
28501da177e4SLinus Torvalds 	sprintf(sdebug_info, "scsi_debug, version %s [%s], "
28511da177e4SLinus Torvalds 		"dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
28521da177e4SLinus Torvalds 		scsi_debug_version_date, scsi_debug_dev_size_mb,
28531da177e4SLinus Torvalds 		scsi_debug_opts);
28541da177e4SLinus Torvalds 	return sdebug_info;
28551da177e4SLinus Torvalds }
28561da177e4SLinus Torvalds 
28571da177e4SLinus Torvalds /* scsi_debug_proc_info
28581da177e4SLinus Torvalds  * Used if the driver currently has no own support for /proc/scsi
28591da177e4SLinus Torvalds  */
2860c8ed555aSAl Viro static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, int length)
28611da177e4SLinus Torvalds {
28621da177e4SLinus Torvalds 	char arr[16];
2863c8ed555aSAl Viro 	int opts;
28641da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
28651da177e4SLinus Torvalds 
28661da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
28671da177e4SLinus Torvalds 		return -EACCES;
28681da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
28691da177e4SLinus Torvalds 	arr[minLen] = '\0';
2870c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
28711da177e4SLinus Torvalds 		return -EINVAL;
2872c8ed555aSAl Viro 	scsi_debug_opts = opts;
28731da177e4SLinus Torvalds 	if (scsi_debug_every_nth != 0)
28741da177e4SLinus Torvalds 		scsi_debug_cmnd_count = 0;
28751da177e4SLinus Torvalds 	return length;
28761da177e4SLinus Torvalds }
2877c8ed555aSAl Viro 
2878c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
2879c8ed555aSAl Viro {
2880c8ed555aSAl Viro 	seq_printf(m, "scsi_debug adapter driver, version "
28811da177e4SLinus Torvalds 	    "%s [%s]\n"
28821da177e4SLinus Torvalds 	    "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
28831da177e4SLinus Torvalds 	    "every_nth=%d(curr:%d)\n"
28841da177e4SLinus Torvalds 	    "delay=%d, max_luns=%d, scsi_level=%d\n"
28851da177e4SLinus Torvalds 	    "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
28861da177e4SLinus Torvalds 	    "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2887c6a44287SMartin K. Petersen 	    "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n",
28881da177e4SLinus Torvalds 	    SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
28891da177e4SLinus Torvalds 	    scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
28901da177e4SLinus Torvalds 	    scsi_debug_cmnd_count, scsi_debug_delay,
28911da177e4SLinus Torvalds 	    scsi_debug_max_luns, scsi_debug_scsi_level,
2892597136abSMartin K. Petersen 	    scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
2893597136abSMartin K. Petersen 	    sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
2894c6a44287SMartin K. Petersen 	    num_host_resets, dix_reads, dix_writes, dif_errors);
2895c8ed555aSAl Viro 	return 0;
28961da177e4SLinus Torvalds }
28971da177e4SLinus Torvalds 
289882069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
28991da177e4SLinus Torvalds {
29001da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
29011da177e4SLinus Torvalds }
29021da177e4SLinus Torvalds 
290382069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
290482069379SAkinobu Mita 			   size_t count)
29051da177e4SLinus Torvalds {
29061da177e4SLinus Torvalds         int delay;
29071da177e4SLinus Torvalds 	char work[20];
29081da177e4SLinus Torvalds 
29091da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
29101da177e4SLinus Torvalds 		if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
29111da177e4SLinus Torvalds 			scsi_debug_delay = delay;
29121da177e4SLinus Torvalds 			return count;
29131da177e4SLinus Torvalds 		}
29141da177e4SLinus Torvalds 	}
29151da177e4SLinus Torvalds 	return -EINVAL;
29161da177e4SLinus Torvalds }
291782069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
29181da177e4SLinus Torvalds 
291982069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
29201da177e4SLinus Torvalds {
29211da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
29221da177e4SLinus Torvalds }
29231da177e4SLinus Torvalds 
292482069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
292582069379SAkinobu Mita 			  size_t count)
29261da177e4SLinus Torvalds {
29271da177e4SLinus Torvalds         int opts;
29281da177e4SLinus Torvalds 	char work[20];
29291da177e4SLinus Torvalds 
29301da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
29311da177e4SLinus Torvalds 		if (0 == strnicmp(work,"0x", 2)) {
29321da177e4SLinus Torvalds 			if (1 == sscanf(&work[2], "%x", &opts))
29331da177e4SLinus Torvalds 				goto opts_done;
29341da177e4SLinus Torvalds 		} else {
29351da177e4SLinus Torvalds 			if (1 == sscanf(work, "%d", &opts))
29361da177e4SLinus Torvalds 				goto opts_done;
29371da177e4SLinus Torvalds 		}
29381da177e4SLinus Torvalds 	}
29391da177e4SLinus Torvalds 	return -EINVAL;
29401da177e4SLinus Torvalds opts_done:
29411da177e4SLinus Torvalds 	scsi_debug_opts = opts;
29421da177e4SLinus Torvalds 	scsi_debug_cmnd_count = 0;
29431da177e4SLinus Torvalds 	return count;
29441da177e4SLinus Torvalds }
294582069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
29461da177e4SLinus Torvalds 
294782069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
29481da177e4SLinus Torvalds {
29491da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
29501da177e4SLinus Torvalds }
295182069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
295282069379SAkinobu Mita 			   size_t count)
29531da177e4SLinus Torvalds {
29541da177e4SLinus Torvalds         int n;
29551da177e4SLinus Torvalds 
29561da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
29571da177e4SLinus Torvalds 		scsi_debug_ptype = n;
29581da177e4SLinus Torvalds 		return count;
29591da177e4SLinus Torvalds 	}
29601da177e4SLinus Torvalds 	return -EINVAL;
29611da177e4SLinus Torvalds }
296282069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
29631da177e4SLinus Torvalds 
296482069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
29651da177e4SLinus Torvalds {
29661da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
29671da177e4SLinus Torvalds }
296882069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
296982069379SAkinobu Mita 			    size_t count)
29701da177e4SLinus Torvalds {
29711da177e4SLinus Torvalds         int n;
29721da177e4SLinus Torvalds 
29731da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
29741da177e4SLinus Torvalds 		scsi_debug_dsense = n;
29751da177e4SLinus Torvalds 		return count;
29761da177e4SLinus Torvalds 	}
29771da177e4SLinus Torvalds 	return -EINVAL;
29781da177e4SLinus Torvalds }
297982069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
29801da177e4SLinus Torvalds 
298182069379SAkinobu Mita static ssize_t 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 }
298582069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
298682069379SAkinobu Mita 			     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 }
299682069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
299723183910SDouglas Gilbert 
299882069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
2999c65b1445SDouglas Gilbert {
3000c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
3001c65b1445SDouglas Gilbert }
300282069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
300382069379SAkinobu Mita 			      size_t count)
3004c65b1445SDouglas Gilbert {
3005c65b1445SDouglas Gilbert         int n;
3006c65b1445SDouglas Gilbert 
3007c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3008c65b1445SDouglas Gilbert 		scsi_debug_no_lun_0 = n;
3009c65b1445SDouglas Gilbert 		return count;
3010c65b1445SDouglas Gilbert 	}
3011c65b1445SDouglas Gilbert 	return -EINVAL;
3012c65b1445SDouglas Gilbert }
301382069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
3014c65b1445SDouglas Gilbert 
301582069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
30161da177e4SLinus Torvalds {
30171da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
30181da177e4SLinus Torvalds }
301982069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
302082069379SAkinobu Mita 			      size_t count)
30211da177e4SLinus Torvalds {
30221da177e4SLinus Torvalds         int n;
30231da177e4SLinus Torvalds 
30241da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
30251da177e4SLinus Torvalds 		scsi_debug_num_tgts = n;
30261da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
30271da177e4SLinus Torvalds 		return count;
30281da177e4SLinus Torvalds 	}
30291da177e4SLinus Torvalds 	return -EINVAL;
30301da177e4SLinus Torvalds }
303182069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
30321da177e4SLinus Torvalds 
303382069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
30341da177e4SLinus Torvalds {
30351da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
30361da177e4SLinus Torvalds }
303782069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
30381da177e4SLinus Torvalds 
303982069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
30401da177e4SLinus Torvalds {
30411da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
30421da177e4SLinus Torvalds }
304382069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
30441da177e4SLinus Torvalds 
304582069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
30461da177e4SLinus Torvalds {
30471da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
30481da177e4SLinus Torvalds }
304982069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
305082069379SAkinobu Mita 			       size_t count)
30511da177e4SLinus Torvalds {
30521da177e4SLinus Torvalds         int nth;
30531da177e4SLinus Torvalds 
30541da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
30551da177e4SLinus Torvalds 		scsi_debug_every_nth = nth;
30561da177e4SLinus Torvalds 		scsi_debug_cmnd_count = 0;
30571da177e4SLinus Torvalds 		return count;
30581da177e4SLinus Torvalds 	}
30591da177e4SLinus Torvalds 	return -EINVAL;
30601da177e4SLinus Torvalds }
306182069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
30621da177e4SLinus Torvalds 
306382069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
30641da177e4SLinus Torvalds {
30651da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
30661da177e4SLinus Torvalds }
306782069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
306882069379SAkinobu Mita 			      size_t count)
30691da177e4SLinus Torvalds {
30701da177e4SLinus Torvalds         int n;
30711da177e4SLinus Torvalds 
30721da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
30731da177e4SLinus Torvalds 		scsi_debug_max_luns = n;
30741da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
30751da177e4SLinus Torvalds 		return count;
30761da177e4SLinus Torvalds 	}
30771da177e4SLinus Torvalds 	return -EINVAL;
30781da177e4SLinus Torvalds }
307982069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
30801da177e4SLinus Torvalds 
308182069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
308278d4e5a0SDouglas Gilbert {
308378d4e5a0SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue);
308478d4e5a0SDouglas Gilbert }
308582069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
308682069379SAkinobu Mita 			       size_t count)
308778d4e5a0SDouglas Gilbert {
308878d4e5a0SDouglas Gilbert         int n;
308978d4e5a0SDouglas Gilbert 
309078d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
309178d4e5a0SDouglas Gilbert 	    (n <= SCSI_DEBUG_CANQUEUE)) {
309278d4e5a0SDouglas Gilbert 		scsi_debug_max_queue = n;
309378d4e5a0SDouglas Gilbert 		return count;
309478d4e5a0SDouglas Gilbert 	}
309578d4e5a0SDouglas Gilbert 	return -EINVAL;
309678d4e5a0SDouglas Gilbert }
309782069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
309878d4e5a0SDouglas Gilbert 
309982069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
310078d4e5a0SDouglas Gilbert {
310178d4e5a0SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld);
310278d4e5a0SDouglas Gilbert }
310382069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
310478d4e5a0SDouglas Gilbert 
310582069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
31061da177e4SLinus Torvalds {
31071da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
31081da177e4SLinus Torvalds }
310982069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
31101da177e4SLinus Torvalds 
311182069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
3112c65b1445SDouglas Gilbert {
3113c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
3114c65b1445SDouglas Gilbert }
311582069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
311682069379SAkinobu Mita 				size_t count)
3117c65b1445SDouglas Gilbert {
3118c65b1445SDouglas Gilbert         int n;
3119c65b1445SDouglas Gilbert 
3120c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3121c65b1445SDouglas Gilbert 		scsi_debug_virtual_gb = n;
312228898873SFUJITA Tomonori 
312328898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
312428898873SFUJITA Tomonori 
3125c65b1445SDouglas Gilbert 		return count;
3126c65b1445SDouglas Gilbert 	}
3127c65b1445SDouglas Gilbert 	return -EINVAL;
3128c65b1445SDouglas Gilbert }
312982069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
3130c65b1445SDouglas Gilbert 
313182069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
31321da177e4SLinus Torvalds {
31331da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
31341da177e4SLinus Torvalds }
31351da177e4SLinus Torvalds 
313682069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
313782069379SAkinobu Mita 			      size_t count)
31381da177e4SLinus Torvalds {
31391da177e4SLinus Torvalds 	int delta_hosts;
31401da177e4SLinus Torvalds 
3141f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
31421da177e4SLinus Torvalds 		return -EINVAL;
31431da177e4SLinus Torvalds 	if (delta_hosts > 0) {
31441da177e4SLinus Torvalds 		do {
31451da177e4SLinus Torvalds 			sdebug_add_adapter();
31461da177e4SLinus Torvalds 		} while (--delta_hosts);
31471da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
31481da177e4SLinus Torvalds 		do {
31491da177e4SLinus Torvalds 			sdebug_remove_adapter();
31501da177e4SLinus Torvalds 		} while (++delta_hosts);
31511da177e4SLinus Torvalds 	}
31521da177e4SLinus Torvalds 	return count;
31531da177e4SLinus Torvalds }
315482069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
31551da177e4SLinus Torvalds 
315682069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
315723183910SDouglas Gilbert {
315823183910SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
315923183910SDouglas Gilbert }
316082069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
316182069379SAkinobu Mita 				    size_t count)
316223183910SDouglas Gilbert {
316323183910SDouglas Gilbert 	int n;
316423183910SDouglas Gilbert 
316523183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
316623183910SDouglas Gilbert 		scsi_debug_vpd_use_hostno = n;
316723183910SDouglas Gilbert 		return count;
316823183910SDouglas Gilbert 	}
316923183910SDouglas Gilbert 	return -EINVAL;
317023183910SDouglas Gilbert }
317182069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
317223183910SDouglas Gilbert 
317382069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
3174597136abSMartin K. Petersen {
3175597136abSMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
3176597136abSMartin K. Petersen }
317782069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
3178597136abSMartin K. Petersen 
317982069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
3180c6a44287SMartin K. Petersen {
3181c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
3182c6a44287SMartin K. Petersen }
318382069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
3184c6a44287SMartin K. Petersen 
318582069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
3186c6a44287SMartin K. Petersen {
3187c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
3188c6a44287SMartin K. Petersen }
318982069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
3190c6a44287SMartin K. Petersen 
319182069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
3192c6a44287SMartin K. Petersen {
319368aee7baSAkinobu Mita 	return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_guard);
3194c6a44287SMartin K. Petersen }
319582069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
3196c6a44287SMartin K. Petersen 
319782069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
3198c6a44287SMartin K. Petersen {
3199c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
3200c6a44287SMartin K. Petersen }
320182069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
3202c6a44287SMartin K. Petersen 
320382069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
320444d92694SMartin K. Petersen {
320544d92694SMartin K. Petersen 	ssize_t count;
320644d92694SMartin K. Petersen 
32075b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
320844d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
320944d92694SMartin K. Petersen 				 sdebug_store_sectors);
321044d92694SMartin K. Petersen 
321144d92694SMartin K. Petersen 	count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
321244d92694SMartin K. Petersen 
321344d92694SMartin K. Petersen 	buf[count++] = '\n';
321444d92694SMartin K. Petersen 	buf[count++] = 0;
321544d92694SMartin K. Petersen 
321644d92694SMartin K. Petersen 	return count;
321744d92694SMartin K. Petersen }
321882069379SAkinobu Mita static DRIVER_ATTR_RO(map);
321944d92694SMartin K. Petersen 
322082069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
3221d986788bSMartin Pitt {
3222d986788bSMartin Pitt 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_removable ? 1 : 0);
3223d986788bSMartin Pitt }
322482069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
322582069379SAkinobu Mita 			       size_t count)
3226d986788bSMartin Pitt {
3227d986788bSMartin Pitt 	int n;
3228d986788bSMartin Pitt 
3229d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3230d986788bSMartin Pitt 		scsi_debug_removable = (n > 0);
3231d986788bSMartin Pitt 		return count;
3232d986788bSMartin Pitt 	}
3233d986788bSMartin Pitt 	return -EINVAL;
3234d986788bSMartin Pitt }
323582069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
3236d986788bSMartin Pitt 
323782069379SAkinobu Mita /* Note: The following array creates attribute files in the
323823183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
323923183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
324023183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
324123183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
324223183910SDouglas Gilbert  */
32436ecaff7fSRandy Dunlap 
324482069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
324582069379SAkinobu Mita 	&driver_attr_delay.attr,
324682069379SAkinobu Mita 	&driver_attr_opts.attr,
324782069379SAkinobu Mita 	&driver_attr_ptype.attr,
324882069379SAkinobu Mita 	&driver_attr_dsense.attr,
324982069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
325082069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
325182069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
325282069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
325382069379SAkinobu Mita 	&driver_attr_num_parts.attr,
325482069379SAkinobu Mita 	&driver_attr_every_nth.attr,
325582069379SAkinobu Mita 	&driver_attr_max_luns.attr,
325682069379SAkinobu Mita 	&driver_attr_max_queue.attr,
325782069379SAkinobu Mita 	&driver_attr_no_uld.attr,
325882069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
325982069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
326082069379SAkinobu Mita 	&driver_attr_add_host.attr,
326182069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
326282069379SAkinobu Mita 	&driver_attr_sector_size.attr,
326382069379SAkinobu Mita 	&driver_attr_dix.attr,
326482069379SAkinobu Mita 	&driver_attr_dif.attr,
326582069379SAkinobu Mita 	&driver_attr_guard.attr,
326682069379SAkinobu Mita 	&driver_attr_ato.attr,
326782069379SAkinobu Mita 	&driver_attr_map.attr,
326882069379SAkinobu Mita 	&driver_attr_removable.attr,
326982069379SAkinobu Mita 	NULL,
327082069379SAkinobu Mita };
327182069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
32721da177e4SLinus Torvalds 
327311ddcecaSAkinobu Mita static struct device *pseudo_primary;
32748dea0d02SFUJITA Tomonori 
32751da177e4SLinus Torvalds static int __init scsi_debug_init(void)
32761da177e4SLinus Torvalds {
32775f2578e5SFUJITA Tomonori 	unsigned long sz;
32781da177e4SLinus Torvalds 	int host_to_add;
32791da177e4SLinus Torvalds 	int k;
32806ecaff7fSRandy Dunlap 	int ret;
32811da177e4SLinus Torvalds 
3282597136abSMartin K. Petersen 	switch (scsi_debug_sector_size) {
3283597136abSMartin K. Petersen 	case  512:
3284597136abSMartin K. Petersen 	case 1024:
3285597136abSMartin K. Petersen 	case 2048:
3286597136abSMartin K. Petersen 	case 4096:
3287597136abSMartin K. Petersen 		break;
3288597136abSMartin K. Petersen 	default:
3289c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n",
3290597136abSMartin K. Petersen 		       scsi_debug_sector_size);
3291597136abSMartin K. Petersen 		return -EINVAL;
3292597136abSMartin K. Petersen 	}
3293597136abSMartin K. Petersen 
3294c6a44287SMartin K. Petersen 	switch (scsi_debug_dif) {
3295c6a44287SMartin K. Petersen 
3296c6a44287SMartin K. Petersen 	case SD_DIF_TYPE0_PROTECTION:
3297c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
3298395cef03SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
3299c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
3300c6a44287SMartin K. Petersen 		break;
3301c6a44287SMartin K. Petersen 
3302c6a44287SMartin K. Petersen 	default:
3303395cef03SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n");
3304c6a44287SMartin K. Petersen 		return -EINVAL;
3305c6a44287SMartin K. Petersen 	}
3306c6a44287SMartin K. Petersen 
3307c6a44287SMartin K. Petersen 	if (scsi_debug_guard > 1) {
3308c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n");
3309c6a44287SMartin K. Petersen 		return -EINVAL;
3310c6a44287SMartin K. Petersen 	}
3311c6a44287SMartin K. Petersen 
3312c6a44287SMartin K. Petersen 	if (scsi_debug_ato > 1) {
3313c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n");
3314c6a44287SMartin K. Petersen 		return -EINVAL;
3315c6a44287SMartin K. Petersen 	}
3316c6a44287SMartin K. Petersen 
3317ea61fca5SMartin K. Petersen 	if (scsi_debug_physblk_exp > 15) {
3318ea61fca5SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n",
3319ea61fca5SMartin K. Petersen 		       scsi_debug_physblk_exp);
3320ea61fca5SMartin K. Petersen 		return -EINVAL;
3321ea61fca5SMartin K. Petersen 	}
3322ea61fca5SMartin K. Petersen 
3323ea61fca5SMartin K. Petersen 	if (scsi_debug_lowest_aligned > 0x3fff) {
3324ea61fca5SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n",
3325ea61fca5SMartin K. Petersen 		       scsi_debug_lowest_aligned);
3326ea61fca5SMartin K. Petersen 		return -EINVAL;
3327ea61fca5SMartin K. Petersen 	}
3328ea61fca5SMartin K. Petersen 
33291da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb < 1)
33301da177e4SLinus Torvalds 		scsi_debug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
33315f2578e5SFUJITA Tomonori 	sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
3332597136abSMartin K. Petersen 	sdebug_store_sectors = sz / scsi_debug_sector_size;
333328898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
33341da177e4SLinus Torvalds 
33351da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
33361da177e4SLinus Torvalds 	sdebug_heads = 8;
33371da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
33381da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb >= 16)
33391da177e4SLinus Torvalds 		sdebug_heads = 32;
33401da177e4SLinus Torvalds 	else if (scsi_debug_dev_size_mb >= 256)
33411da177e4SLinus Torvalds 		sdebug_heads = 64;
33421da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
33431da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
33441da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
33451da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
33461da177e4SLinus Torvalds 		sdebug_heads = 255;
33471da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
33481da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
33491da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
33501da177e4SLinus Torvalds 	}
33511da177e4SLinus Torvalds 
33521da177e4SLinus Torvalds 	fake_storep = vmalloc(sz);
33531da177e4SLinus Torvalds 	if (NULL == fake_storep) {
33541da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
33551da177e4SLinus Torvalds 		return -ENOMEM;
33561da177e4SLinus Torvalds 	}
33571da177e4SLinus Torvalds 	memset(fake_storep, 0, sz);
33581da177e4SLinus Torvalds 	if (scsi_debug_num_parts > 0)
3359f58b0efbSFUJITA Tomonori 		sdebug_build_parts(fake_storep, sz);
33601da177e4SLinus Torvalds 
33617cb69d03SAkinobu Mita 	if (scsi_debug_dix) {
3362c6a44287SMartin K. Petersen 		int dif_size;
3363c6a44287SMartin K. Petersen 
3364c6a44287SMartin K. Petersen 		dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
3365c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
3366c6a44287SMartin K. Petersen 
3367c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n",
3368c6a44287SMartin K. Petersen 		       dif_size, dif_storep);
3369c6a44287SMartin K. Petersen 
3370c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
3371c6a44287SMartin K. Petersen 			printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n");
3372c6a44287SMartin K. Petersen 			ret = -ENOMEM;
3373c6a44287SMartin K. Petersen 			goto free_vm;
3374c6a44287SMartin K. Petersen 		}
3375c6a44287SMartin K. Petersen 
3376c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
3377c6a44287SMartin K. Petersen 	}
3378c6a44287SMartin K. Petersen 
33795b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
33805b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
33816014759cSMartin K. Petersen 		scsi_debug_unmap_max_blocks =
33826014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU);
33836014759cSMartin K. Petersen 
33846014759cSMartin K. Petersen 		scsi_debug_unmap_max_desc =
33856014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_max_desc, 0U, 256U);
33866014759cSMartin K. Petersen 
33876014759cSMartin K. Petersen 		scsi_debug_unmap_granularity =
33886014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU);
33896014759cSMartin K. Petersen 
33906014759cSMartin K. Petersen 		if (scsi_debug_unmap_alignment &&
3391ac17078aSAkinobu Mita 		    scsi_debug_unmap_granularity <=
3392ac17078aSAkinobu Mita 		    scsi_debug_unmap_alignment) {
339344d92694SMartin K. Petersen 			printk(KERN_ERR
3394ac17078aSAkinobu Mita 			       "%s: ERR: unmap_granularity <= unmap_alignment\n",
339544d92694SMartin K. Petersen 			       __func__);
339644d92694SMartin K. Petersen 			return -EINVAL;
339744d92694SMartin K. Petersen 		}
339844d92694SMartin K. Petersen 
3399b90ebc3dSAkinobu Mita 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
3400b90ebc3dSAkinobu Mita 		map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
340144d92694SMartin K. Petersen 
340244d92694SMartin K. Petersen 		printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n",
340344d92694SMartin K. Petersen 		       map_size);
340444d92694SMartin K. Petersen 
340544d92694SMartin K. Petersen 		if (map_storep == NULL) {
340644d92694SMartin K. Petersen 			printk(KERN_ERR "scsi_debug_init: out of mem. (MAP)\n");
340744d92694SMartin K. Petersen 			ret = -ENOMEM;
340844d92694SMartin K. Petersen 			goto free_vm;
340944d92694SMartin K. Petersen 		}
341044d92694SMartin K. Petersen 
3411b90ebc3dSAkinobu Mita 		bitmap_zero(map_storep, map_size);
341244d92694SMartin K. Petersen 
341344d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
341444d92694SMartin K. Petersen 		if (scsi_debug_num_parts)
341544d92694SMartin K. Petersen 			map_region(0, 2);
341644d92694SMartin K. Petersen 	}
341744d92694SMartin K. Petersen 
34189b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
34199b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
34209b906779SNicholas Bellinger 		printk(KERN_WARNING "scsi_debug: root_device_register() error\n");
34219b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
34226ecaff7fSRandy Dunlap 		goto free_vm;
34236ecaff7fSRandy Dunlap 	}
34246ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
34256ecaff7fSRandy Dunlap 	if (ret < 0) {
34266ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
34276ecaff7fSRandy Dunlap 			ret);
34286ecaff7fSRandy Dunlap 		goto dev_unreg;
34296ecaff7fSRandy Dunlap 	}
34306ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
34316ecaff7fSRandy Dunlap 	if (ret < 0) {
34326ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
34336ecaff7fSRandy Dunlap 			ret);
34346ecaff7fSRandy Dunlap 		goto bus_unreg;
34356ecaff7fSRandy Dunlap 	}
34361da177e4SLinus Torvalds 
34376ecaff7fSRandy Dunlap 	init_all_queued();
34381da177e4SLinus Torvalds 
34391da177e4SLinus Torvalds 	host_to_add = scsi_debug_add_host;
34401da177e4SLinus Torvalds         scsi_debug_add_host = 0;
34411da177e4SLinus Torvalds 
34421da177e4SLinus Torvalds         for (k = 0; k < host_to_add; k++) {
34431da177e4SLinus Torvalds                 if (sdebug_add_adapter()) {
34441da177e4SLinus Torvalds                         printk(KERN_ERR "scsi_debug_init: "
34451da177e4SLinus Torvalds                                "sdebug_add_adapter failed k=%d\n", k);
34461da177e4SLinus Torvalds                         break;
34471da177e4SLinus Torvalds                 }
34481da177e4SLinus Torvalds         }
34491da177e4SLinus Torvalds 
34501da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
34511da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
34521da177e4SLinus Torvalds 		       scsi_debug_add_host);
34531da177e4SLinus Torvalds 	}
34541da177e4SLinus Torvalds 	return 0;
34556ecaff7fSRandy Dunlap 
34566ecaff7fSRandy Dunlap bus_unreg:
34576ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
34586ecaff7fSRandy Dunlap dev_unreg:
34599b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
34606ecaff7fSRandy Dunlap free_vm:
346144d92694SMartin K. Petersen 	if (map_storep)
346244d92694SMartin K. Petersen 		vfree(map_storep);
3463c6a44287SMartin K. Petersen 	if (dif_storep)
3464c6a44287SMartin K. Petersen 		vfree(dif_storep);
34656ecaff7fSRandy Dunlap 	vfree(fake_storep);
34666ecaff7fSRandy Dunlap 
34676ecaff7fSRandy Dunlap 	return ret;
34681da177e4SLinus Torvalds }
34691da177e4SLinus Torvalds 
34701da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
34711da177e4SLinus Torvalds {
34721da177e4SLinus Torvalds 	int k = scsi_debug_add_host;
34731da177e4SLinus Torvalds 
34741da177e4SLinus Torvalds 	stop_all_queued();
34751da177e4SLinus Torvalds 	for (; k; k--)
34761da177e4SLinus Torvalds 		sdebug_remove_adapter();
34771da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
34781da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
34799b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
34801da177e4SLinus Torvalds 
3481c6a44287SMartin K. Petersen 	if (dif_storep)
3482c6a44287SMartin K. Petersen 		vfree(dif_storep);
3483c6a44287SMartin K. Petersen 
34841da177e4SLinus Torvalds 	vfree(fake_storep);
34851da177e4SLinus Torvalds }
34861da177e4SLinus Torvalds 
34871da177e4SLinus Torvalds device_initcall(scsi_debug_init);
34881da177e4SLinus Torvalds module_exit(scsi_debug_exit);
34891da177e4SLinus Torvalds 
34901da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev)
34911da177e4SLinus Torvalds {
34921da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
34931da177e4SLinus Torvalds 
34941da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
34951da177e4SLinus Torvalds         kfree(sdbg_host);
34961da177e4SLinus Torvalds }
34971da177e4SLinus Torvalds 
34981da177e4SLinus Torvalds static int sdebug_add_adapter(void)
34991da177e4SLinus Torvalds {
35001da177e4SLinus Torvalds 	int k, devs_per_host;
35011da177e4SLinus Torvalds         int error = 0;
35021da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
35038b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
35041da177e4SLinus Torvalds 
350524669f75SJes Sorensen         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
35061da177e4SLinus Torvalds         if (NULL == sdbg_host) {
35071da177e4SLinus Torvalds                 printk(KERN_ERR "%s: out of memory at line %d\n",
3508cadbd4a5SHarvey Harrison                        __func__, __LINE__);
35091da177e4SLinus Torvalds                 return -ENOMEM;
35101da177e4SLinus Torvalds         }
35111da177e4SLinus Torvalds 
35121da177e4SLinus Torvalds         INIT_LIST_HEAD(&sdbg_host->dev_info_list);
35131da177e4SLinus Torvalds 
35141da177e4SLinus Torvalds 	devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
35151da177e4SLinus Torvalds         for (k = 0; k < devs_per_host; k++) {
35165cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
35175cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
35181da177e4SLinus Torvalds                         printk(KERN_ERR "%s: out of memory at line %d\n",
3519cadbd4a5SHarvey Harrison                                __func__, __LINE__);
35201da177e4SLinus Torvalds                         error = -ENOMEM;
35211da177e4SLinus Torvalds 			goto clean;
35221da177e4SLinus Torvalds                 }
35231da177e4SLinus Torvalds         }
35241da177e4SLinus Torvalds 
35251da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
35261da177e4SLinus Torvalds         list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
35271da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
35281da177e4SLinus Torvalds 
35291da177e4SLinus Torvalds         sdbg_host->dev.bus = &pseudo_lld_bus;
35309b906779SNicholas Bellinger         sdbg_host->dev.parent = pseudo_primary;
35311da177e4SLinus Torvalds         sdbg_host->dev.release = &sdebug_release_adapter;
353271610f55SKay Sievers         dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
35331da177e4SLinus Torvalds 
35341da177e4SLinus Torvalds         error = device_register(&sdbg_host->dev);
35351da177e4SLinus Torvalds 
35361da177e4SLinus Torvalds         if (error)
35371da177e4SLinus Torvalds 		goto clean;
35381da177e4SLinus Torvalds 
35391da177e4SLinus Torvalds 	++scsi_debug_add_host;
35401da177e4SLinus Torvalds         return error;
35411da177e4SLinus Torvalds 
35421da177e4SLinus Torvalds clean:
35438b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
35448b40228fSFUJITA Tomonori 				 dev_list) {
35451da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
35461da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
35471da177e4SLinus Torvalds 	}
35481da177e4SLinus Torvalds 
35491da177e4SLinus Torvalds 	kfree(sdbg_host);
35501da177e4SLinus Torvalds         return error;
35511da177e4SLinus Torvalds }
35521da177e4SLinus Torvalds 
35531da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
35541da177e4SLinus Torvalds {
35551da177e4SLinus Torvalds         struct sdebug_host_info * sdbg_host = NULL;
35561da177e4SLinus Torvalds 
35571da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
35581da177e4SLinus Torvalds         if (!list_empty(&sdebug_host_list)) {
35591da177e4SLinus Torvalds                 sdbg_host = list_entry(sdebug_host_list.prev,
35601da177e4SLinus Torvalds                                        struct sdebug_host_info, host_list);
35611da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
35621da177e4SLinus Torvalds 	}
35631da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
35641da177e4SLinus Torvalds 
35651da177e4SLinus Torvalds 	if (!sdbg_host)
35661da177e4SLinus Torvalds 		return;
35671da177e4SLinus Torvalds 
35681da177e4SLinus Torvalds         device_unregister(&sdbg_host->dev);
35691da177e4SLinus Torvalds         --scsi_debug_add_host;
35701da177e4SLinus Torvalds }
35711da177e4SLinus Torvalds 
3572639db475SFUJITA Tomonori static
3573f281233dSJeff Garzik int scsi_debug_queuecommand_lck(struct scsi_cmnd *SCpnt, done_funct_t done)
3574639db475SFUJITA Tomonori {
3575639db475SFUJITA Tomonori 	unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
3576639db475SFUJITA Tomonori 	int len, k;
3577639db475SFUJITA Tomonori 	unsigned int num;
3578639db475SFUJITA Tomonori 	unsigned long long lba;
3579395cef03SMartin K. Petersen 	u32 ei_lba;
3580639db475SFUJITA Tomonori 	int errsts = 0;
3581639db475SFUJITA Tomonori 	int target = SCpnt->device->id;
3582639db475SFUJITA Tomonori 	struct sdebug_dev_info *devip = NULL;
3583639db475SFUJITA Tomonori 	int inj_recovered = 0;
3584639db475SFUJITA Tomonori 	int inj_transport = 0;
3585c6a44287SMartin K. Petersen 	int inj_dif = 0;
3586c6a44287SMartin K. Petersen 	int inj_dix = 0;
3587b57d7c01SChristoph Hellwig 	int inj_short = 0;
3588639db475SFUJITA Tomonori 	int delay_override = 0;
358944d92694SMartin K. Petersen 	int unmap = 0;
3590639db475SFUJITA Tomonori 
3591639db475SFUJITA Tomonori 	scsi_set_resid(SCpnt, 0);
3592639db475SFUJITA Tomonori 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
3593639db475SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: cmd ");
3594639db475SFUJITA Tomonori 		for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
3595639db475SFUJITA Tomonori 			printk("%02x ", (int)cmd[k]);
3596639db475SFUJITA Tomonori 		printk("\n");
3597639db475SFUJITA Tomonori 	}
3598639db475SFUJITA Tomonori 
3599639db475SFUJITA Tomonori 	if (target == SCpnt->device->host->hostt->this_id) {
3600639db475SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: initiator's id used as "
3601639db475SFUJITA Tomonori 		       "target!\n");
3602639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
3603639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
3604639db475SFUJITA Tomonori 	}
3605639db475SFUJITA Tomonori 
3606639db475SFUJITA Tomonori 	if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
3607639db475SFUJITA Tomonori 	    (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
3608639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
3609639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
3610639db475SFUJITA Tomonori 	devip = devInfoReg(SCpnt->device);
3611639db475SFUJITA Tomonori 	if (NULL == devip)
3612639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
3613639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
3614639db475SFUJITA Tomonori 
3615639db475SFUJITA Tomonori 	if ((scsi_debug_every_nth != 0) &&
3616639db475SFUJITA Tomonori 	    (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
3617639db475SFUJITA Tomonori 		scsi_debug_cmnd_count = 0;
3618639db475SFUJITA Tomonori 		if (scsi_debug_every_nth < -1)
3619639db475SFUJITA Tomonori 			scsi_debug_every_nth = -1;
3620639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
3621639db475SFUJITA Tomonori 			return 0; /* ignore command causing timeout */
362218a4d0a2SMartin K. Petersen 		else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts &&
362318a4d0a2SMartin K. Petersen 			 scsi_medium_access_command(SCpnt))
362418a4d0a2SMartin K. Petersen 			return 0; /* time out reads and writes */
3625639db475SFUJITA Tomonori 		else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
3626639db475SFUJITA Tomonori 			inj_recovered = 1; /* to reads and writes below */
3627639db475SFUJITA Tomonori 		else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
3628639db475SFUJITA Tomonori 			inj_transport = 1; /* to reads and writes below */
3629c6a44287SMartin K. Petersen 		else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
3630c6a44287SMartin K. Petersen 			inj_dif = 1; /* to reads and writes below */
3631c6a44287SMartin K. Petersen 		else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
3632c6a44287SMartin K. Petersen 			inj_dix = 1; /* to reads and writes below */
3633b57d7c01SChristoph Hellwig 		else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & scsi_debug_opts)
3634b57d7c01SChristoph Hellwig 			inj_short = 1;
3635639db475SFUJITA Tomonori 	}
3636639db475SFUJITA Tomonori 
3637639db475SFUJITA Tomonori 	if (devip->wlun) {
3638639db475SFUJITA Tomonori 		switch (*cmd) {
3639639db475SFUJITA Tomonori 		case INQUIRY:
3640639db475SFUJITA Tomonori 		case REQUEST_SENSE:
3641639db475SFUJITA Tomonori 		case TEST_UNIT_READY:
3642639db475SFUJITA Tomonori 		case REPORT_LUNS:
3643639db475SFUJITA Tomonori 			break;  /* only allowable wlun commands */
3644639db475SFUJITA Tomonori 		default:
3645639db475SFUJITA Tomonori 			if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3646639db475SFUJITA Tomonori 				printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
3647639db475SFUJITA Tomonori 				       "not supported for wlun\n", *cmd);
3648639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3649639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
3650639db475SFUJITA Tomonori 			errsts = check_condition_result;
3651639db475SFUJITA Tomonori 			return schedule_resp(SCpnt, devip, done, errsts,
3652639db475SFUJITA Tomonori 					     0);
3653639db475SFUJITA Tomonori 		}
3654639db475SFUJITA Tomonori 	}
3655639db475SFUJITA Tomonori 
3656639db475SFUJITA Tomonori 	switch (*cmd) {
3657639db475SFUJITA Tomonori 	case INQUIRY:     /* mandatory, ignore unit attention */
3658639db475SFUJITA Tomonori 		delay_override = 1;
3659639db475SFUJITA Tomonori 		errsts = resp_inquiry(SCpnt, target, devip);
3660639db475SFUJITA Tomonori 		break;
3661639db475SFUJITA Tomonori 	case REQUEST_SENSE:	/* mandatory, ignore unit attention */
3662639db475SFUJITA Tomonori 		delay_override = 1;
3663639db475SFUJITA Tomonori 		errsts = resp_requests(SCpnt, devip);
3664639db475SFUJITA Tomonori 		break;
3665639db475SFUJITA Tomonori 	case REZERO_UNIT:	/* actually this is REWIND for SSC */
3666639db475SFUJITA Tomonori 	case START_STOP:
3667639db475SFUJITA Tomonori 		errsts = resp_start_stop(SCpnt, devip);
3668639db475SFUJITA Tomonori 		break;
3669639db475SFUJITA Tomonori 	case ALLOW_MEDIUM_REMOVAL:
3670639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3671639db475SFUJITA Tomonori 		if (errsts)
3672639db475SFUJITA Tomonori 			break;
3673639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3674639db475SFUJITA Tomonori 			printk(KERN_INFO "scsi_debug: Medium removal %s\n",
3675639db475SFUJITA Tomonori 			       cmd[4] ? "inhibited" : "enabled");
3676639db475SFUJITA Tomonori 		break;
3677639db475SFUJITA Tomonori 	case SEND_DIAGNOSTIC:     /* mandatory */
3678639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3679639db475SFUJITA Tomonori 		break;
3680639db475SFUJITA Tomonori 	case TEST_UNIT_READY:     /* mandatory */
3681639db475SFUJITA Tomonori 		delay_override = 1;
3682639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3683639db475SFUJITA Tomonori 		break;
3684639db475SFUJITA Tomonori 	case RESERVE:
3685639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3686639db475SFUJITA Tomonori 		break;
3687639db475SFUJITA Tomonori 	case RESERVE_10:
3688639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3689639db475SFUJITA Tomonori 		break;
3690639db475SFUJITA Tomonori 	case RELEASE:
3691639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3692639db475SFUJITA Tomonori 		break;
3693639db475SFUJITA Tomonori 	case RELEASE_10:
3694639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3695639db475SFUJITA Tomonori 		break;
3696639db475SFUJITA Tomonori 	case READ_CAPACITY:
3697639db475SFUJITA Tomonori 		errsts = resp_readcap(SCpnt, devip);
3698639db475SFUJITA Tomonori 		break;
3699639db475SFUJITA Tomonori 	case SERVICE_ACTION_IN:
370044d92694SMartin K. Petersen 		if (cmd[1] == SAI_READ_CAPACITY_16)
370144d92694SMartin K. Petersen 			errsts = resp_readcap16(SCpnt, devip);
370244d92694SMartin K. Petersen 		else if (cmd[1] == SAI_GET_LBA_STATUS) {
370344d92694SMartin K. Petersen 
37045b94e232SMartin K. Petersen 			if (scsi_debug_lbp() == 0) {
370544d92694SMartin K. Petersen 				mk_sense_buffer(devip, ILLEGAL_REQUEST,
370644d92694SMartin K. Petersen 						INVALID_COMMAND_OPCODE, 0);
370744d92694SMartin K. Petersen 				errsts = check_condition_result;
370844d92694SMartin K. Petersen 			} else
370944d92694SMartin K. Petersen 				errsts = resp_get_lba_status(SCpnt, devip);
371044d92694SMartin K. Petersen 		} else {
3711639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3712639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
3713639db475SFUJITA Tomonori 			errsts = check_condition_result;
3714639db475SFUJITA Tomonori 		}
3715639db475SFUJITA Tomonori 		break;
3716639db475SFUJITA Tomonori 	case MAINTENANCE_IN:
3717639db475SFUJITA Tomonori 		if (MI_REPORT_TARGET_PGS != cmd[1]) {
3718639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3719639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
3720639db475SFUJITA Tomonori 			errsts = check_condition_result;
3721639db475SFUJITA Tomonori 			break;
3722639db475SFUJITA Tomonori 		}
3723639db475SFUJITA Tomonori 		errsts = resp_report_tgtpgs(SCpnt, devip);
3724639db475SFUJITA Tomonori 		break;
3725639db475SFUJITA Tomonori 	case READ_16:
3726639db475SFUJITA Tomonori 	case READ_12:
3727639db475SFUJITA Tomonori 	case READ_10:
3728395cef03SMartin K. Petersen 		/* READ{10,12,16} and DIF Type 2 are natural enemies */
3729395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3730395cef03SMartin K. Petersen 		    cmd[1] & 0xe0) {
3731395cef03SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3732395cef03SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
3733395cef03SMartin K. Petersen 			errsts = check_condition_result;
3734395cef03SMartin K. Petersen 			break;
3735395cef03SMartin K. Petersen 		}
3736395cef03SMartin K. Petersen 
3737395cef03SMartin K. Petersen 		if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3738395cef03SMartin K. Petersen 		     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3739395cef03SMartin K. Petersen 		    (cmd[1] & 0xe0) == 0)
3740395cef03SMartin K. Petersen 			printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3741395cef03SMartin K. Petersen 
3742395cef03SMartin K. Petersen 		/* fall through */
3743639db475SFUJITA Tomonori 	case READ_6:
3744395cef03SMartin K. Petersen read:
3745639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3746639db475SFUJITA Tomonori 		if (errsts)
3747639db475SFUJITA Tomonori 			break;
3748639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
3749639db475SFUJITA Tomonori 			break;
3750395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3751b57d7c01SChristoph Hellwig 
3752b57d7c01SChristoph Hellwig 		if (inj_short)
3753b57d7c01SChristoph Hellwig 			num /= 2;
3754b57d7c01SChristoph Hellwig 
3755395cef03SMartin K. Petersen 		errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
3756639db475SFUJITA Tomonori 		if (inj_recovered && (0 == errsts)) {
3757639db475SFUJITA Tomonori 			mk_sense_buffer(devip, RECOVERED_ERROR,
3758639db475SFUJITA Tomonori 					THRESHOLD_EXCEEDED, 0);
3759639db475SFUJITA Tomonori 			errsts = check_condition_result;
3760639db475SFUJITA Tomonori 		} else if (inj_transport && (0 == errsts)) {
3761639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ABORTED_COMMAND,
3762639db475SFUJITA Tomonori 					TRANSPORT_PROBLEM, ACK_NAK_TO);
3763639db475SFUJITA Tomonori 			errsts = check_condition_result;
3764c6a44287SMartin K. Petersen 		} else if (inj_dif && (0 == errsts)) {
3765c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3766c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3767c6a44287SMartin K. Petersen 		} else if (inj_dix && (0 == errsts)) {
3768c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3769c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3770639db475SFUJITA Tomonori 		}
3771639db475SFUJITA Tomonori 		break;
3772639db475SFUJITA Tomonori 	case REPORT_LUNS:	/* mandatory, ignore unit attention */
3773639db475SFUJITA Tomonori 		delay_override = 1;
3774639db475SFUJITA Tomonori 		errsts = resp_report_luns(SCpnt, devip);
3775639db475SFUJITA Tomonori 		break;
3776639db475SFUJITA Tomonori 	case VERIFY:		/* 10 byte SBC-2 command */
3777639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3778639db475SFUJITA Tomonori 		break;
3779639db475SFUJITA Tomonori 	case WRITE_16:
3780639db475SFUJITA Tomonori 	case WRITE_12:
3781639db475SFUJITA Tomonori 	case WRITE_10:
3782395cef03SMartin K. Petersen 		/* WRITE{10,12,16} and DIF Type 2 are natural enemies */
3783395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3784395cef03SMartin K. Petersen 		    cmd[1] & 0xe0) {
3785395cef03SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3786395cef03SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
3787395cef03SMartin K. Petersen 			errsts = check_condition_result;
3788395cef03SMartin K. Petersen 			break;
3789395cef03SMartin K. Petersen 		}
3790395cef03SMartin K. Petersen 
3791395cef03SMartin K. Petersen 		if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3792395cef03SMartin K. Petersen 		     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3793395cef03SMartin K. Petersen 		    (cmd[1] & 0xe0) == 0)
3794395cef03SMartin K. Petersen 			printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3795395cef03SMartin K. Petersen 
3796395cef03SMartin K. Petersen 		/* fall through */
3797639db475SFUJITA Tomonori 	case WRITE_6:
3798395cef03SMartin K. Petersen write:
3799639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3800639db475SFUJITA Tomonori 		if (errsts)
3801639db475SFUJITA Tomonori 			break;
3802639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
3803639db475SFUJITA Tomonori 			break;
3804395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3805395cef03SMartin K. Petersen 		errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
3806639db475SFUJITA Tomonori 		if (inj_recovered && (0 == errsts)) {
3807639db475SFUJITA Tomonori 			mk_sense_buffer(devip, RECOVERED_ERROR,
3808639db475SFUJITA Tomonori 					THRESHOLD_EXCEEDED, 0);
3809639db475SFUJITA Tomonori 			errsts = check_condition_result;
3810c6a44287SMartin K. Petersen 		} else if (inj_dif && (0 == errsts)) {
3811c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3812c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3813c6a44287SMartin K. Petersen 		} else if (inj_dix && (0 == errsts)) {
3814c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3815c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3816639db475SFUJITA Tomonori 		}
3817639db475SFUJITA Tomonori 		break;
381844d92694SMartin K. Petersen 	case WRITE_SAME_16:
38195b94e232SMartin K. Petersen 	case WRITE_SAME:
38206014759cSMartin K. Petersen 		if (cmd[1] & 0x8) {
38215b94e232SMartin K. Petersen 			if ((*cmd == WRITE_SAME_16 && scsi_debug_lbpws == 0) ||
38225b94e232SMartin K. Petersen 			    (*cmd == WRITE_SAME && scsi_debug_lbpws10 == 0)) {
38236014759cSMartin K. Petersen 				mk_sense_buffer(devip, ILLEGAL_REQUEST,
38246014759cSMartin K. Petersen 						INVALID_FIELD_IN_CDB, 0);
38256014759cSMartin K. Petersen 				errsts = check_condition_result;
38266014759cSMartin K. Petersen 			} else
382744d92694SMartin K. Petersen 				unmap = 1;
38286014759cSMartin K. Petersen 		}
38296014759cSMartin K. Petersen 		if (errsts)
38306014759cSMartin K. Petersen 			break;
383144d92694SMartin K. Petersen 		errsts = check_readiness(SCpnt, 0, devip);
383244d92694SMartin K. Petersen 		if (errsts)
383344d92694SMartin K. Petersen 			break;
383444d92694SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
383544d92694SMartin K. Petersen 		errsts = resp_write_same(SCpnt, lba, num, devip, ei_lba, unmap);
383644d92694SMartin K. Petersen 		break;
383744d92694SMartin K. Petersen 	case UNMAP:
383844d92694SMartin K. Petersen 		errsts = check_readiness(SCpnt, 0, devip);
383944d92694SMartin K. Petersen 		if (errsts)
384044d92694SMartin K. Petersen 			break;
384144d92694SMartin K. Petersen 
38425b94e232SMartin K. Petersen 		if (scsi_debug_unmap_max_desc == 0 || scsi_debug_lbpu == 0) {
384344d92694SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
384444d92694SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
384544d92694SMartin K. Petersen 			errsts = check_condition_result;
384644d92694SMartin K. Petersen 		} else
384744d92694SMartin K. Petersen 			errsts = resp_unmap(SCpnt, devip);
384844d92694SMartin K. Petersen 		break;
3849639db475SFUJITA Tomonori 	case MODE_SENSE:
3850639db475SFUJITA Tomonori 	case MODE_SENSE_10:
3851639db475SFUJITA Tomonori 		errsts = resp_mode_sense(SCpnt, target, devip);
3852639db475SFUJITA Tomonori 		break;
3853639db475SFUJITA Tomonori 	case MODE_SELECT:
3854639db475SFUJITA Tomonori 		errsts = resp_mode_select(SCpnt, 1, devip);
3855639db475SFUJITA Tomonori 		break;
3856639db475SFUJITA Tomonori 	case MODE_SELECT_10:
3857639db475SFUJITA Tomonori 		errsts = resp_mode_select(SCpnt, 0, devip);
3858639db475SFUJITA Tomonori 		break;
3859639db475SFUJITA Tomonori 	case LOG_SENSE:
3860639db475SFUJITA Tomonori 		errsts = resp_log_sense(SCpnt, devip);
3861639db475SFUJITA Tomonori 		break;
3862639db475SFUJITA Tomonori 	case SYNCHRONIZE_CACHE:
3863639db475SFUJITA Tomonori 		delay_override = 1;
3864639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3865639db475SFUJITA Tomonori 		break;
3866639db475SFUJITA Tomonori 	case WRITE_BUFFER:
3867639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3868639db475SFUJITA Tomonori 		break;
3869639db475SFUJITA Tomonori 	case XDWRITEREAD_10:
3870639db475SFUJITA Tomonori 		if (!scsi_bidi_cmnd(SCpnt)) {
3871639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3872639db475SFUJITA Tomonori 					INVALID_FIELD_IN_CDB, 0);
3873639db475SFUJITA Tomonori 			errsts = check_condition_result;
3874639db475SFUJITA Tomonori 			break;
3875639db475SFUJITA Tomonori 		}
3876639db475SFUJITA Tomonori 
3877639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3878639db475SFUJITA Tomonori 		if (errsts)
3879639db475SFUJITA Tomonori 			break;
3880639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
3881639db475SFUJITA Tomonori 			break;
3882395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3883395cef03SMartin K. Petersen 		errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
3884639db475SFUJITA Tomonori 		if (errsts)
3885639db475SFUJITA Tomonori 			break;
3886395cef03SMartin K. Petersen 		errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
3887639db475SFUJITA Tomonori 		if (errsts)
3888639db475SFUJITA Tomonori 			break;
3889639db475SFUJITA Tomonori 		errsts = resp_xdwriteread(SCpnt, lba, num, devip);
3890639db475SFUJITA Tomonori 		break;
3891395cef03SMartin K. Petersen 	case VARIABLE_LENGTH_CMD:
3892395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
3893395cef03SMartin K. Petersen 
3894395cef03SMartin K. Petersen 			if ((cmd[10] & 0xe0) == 0)
3895395cef03SMartin K. Petersen 				printk(KERN_ERR
3896395cef03SMartin K. Petersen 				       "Unprotected RD/WR to DIF device\n");
3897395cef03SMartin K. Petersen 
3898395cef03SMartin K. Petersen 			if (cmd[9] == READ_32) {
3899395cef03SMartin K. Petersen 				BUG_ON(SCpnt->cmd_len < 32);
3900395cef03SMartin K. Petersen 				goto read;
3901395cef03SMartin K. Petersen 			}
3902395cef03SMartin K. Petersen 
3903395cef03SMartin K. Petersen 			if (cmd[9] == WRITE_32) {
3904395cef03SMartin K. Petersen 				BUG_ON(SCpnt->cmd_len < 32);
3905395cef03SMartin K. Petersen 				goto write;
3906395cef03SMartin K. Petersen 			}
3907395cef03SMartin K. Petersen 		}
3908395cef03SMartin K. Petersen 
3909395cef03SMartin K. Petersen 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
3910395cef03SMartin K. Petersen 				INVALID_FIELD_IN_CDB, 0);
3911395cef03SMartin K. Petersen 		errsts = check_condition_result;
3912395cef03SMartin K. Petersen 		break;
3913395cef03SMartin K. Petersen 
3914639db475SFUJITA Tomonori 	default:
3915639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3916639db475SFUJITA Tomonori 			printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
3917639db475SFUJITA Tomonori 			       "supported\n", *cmd);
3918639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3919639db475SFUJITA Tomonori 		if (errsts)
3920639db475SFUJITA Tomonori 			break;	/* Unit attention takes precedence */
3921639db475SFUJITA Tomonori 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
3922639db475SFUJITA Tomonori 		errsts = check_condition_result;
3923639db475SFUJITA Tomonori 		break;
3924639db475SFUJITA Tomonori 	}
3925639db475SFUJITA Tomonori 	return schedule_resp(SCpnt, devip, done, errsts,
3926639db475SFUJITA Tomonori 			     (delay_override ? 0 : scsi_debug_delay));
3927639db475SFUJITA Tomonori }
3928639db475SFUJITA Tomonori 
3929f281233dSJeff Garzik static DEF_SCSI_QCMD(scsi_debug_queuecommand)
3930f281233dSJeff Garzik 
39319e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
3932c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
3933c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
39349e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
39359e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
39369e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
39379e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
39389e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
39399e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
39409e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
39419e603ca0SFUJITA Tomonori 	.queuecommand =		scsi_debug_queuecommand,
39429e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
39439e603ca0SFUJITA Tomonori 	.eh_bus_reset_handler = scsi_debug_bus_reset,
39449e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
39459e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
39469e603ca0SFUJITA Tomonori 	.bios_param =		scsi_debug_biosparam,
39479e603ca0SFUJITA Tomonori 	.can_queue =		SCSI_DEBUG_CANQUEUE,
39489e603ca0SFUJITA Tomonori 	.this_id =		7,
39496bb5e6e7SAkinobu Mita 	.sg_tablesize =		SCSI_MAX_SG_CHAIN_SEGMENTS,
39509e603ca0SFUJITA Tomonori 	.cmd_per_lun =		16,
39516bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
39529e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
39539e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
39549e603ca0SFUJITA Tomonori };
39559e603ca0SFUJITA Tomonori 
39561da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev)
39571da177e4SLinus Torvalds {
39581da177e4SLinus Torvalds         int error = 0;
39591da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
39601da177e4SLinus Torvalds         struct Scsi_Host *hpnt;
3961c6a44287SMartin K. Petersen 	int host_prot;
39621da177e4SLinus Torvalds 
39631da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
39641da177e4SLinus Torvalds 
396578d4e5a0SDouglas Gilbert 	sdebug_driver_template.can_queue = scsi_debug_max_queue;
39660759c666SAkinobu Mita 	if (scsi_debug_clustering)
39670759c666SAkinobu Mita 		sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
39681da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
39691da177e4SLinus Torvalds 	if (NULL == hpnt) {
3970cadbd4a5SHarvey Harrison 		printk(KERN_ERR "%s: scsi_register failed\n", __func__);
39711da177e4SLinus Torvalds 		error = -ENODEV;
39721da177e4SLinus Torvalds 		return error;
39731da177e4SLinus Torvalds 	}
39741da177e4SLinus Torvalds 
39751da177e4SLinus Torvalds         sdbg_host->shost = hpnt;
39761da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
39771da177e4SLinus Torvalds 	if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
39781da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts + 1;
39791da177e4SLinus Torvalds 	else
39801da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts;
3981c65b1445SDouglas Gilbert 	hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;	/* = scsi_debug_max_luns; */
39821da177e4SLinus Torvalds 
3983c6a44287SMartin K. Petersen 	host_prot = 0;
3984c6a44287SMartin K. Petersen 
3985c6a44287SMartin K. Petersen 	switch (scsi_debug_dif) {
3986c6a44287SMartin K. Petersen 
3987c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
3988c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE1_PROTECTION;
3989c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
3990c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE1_PROTECTION;
3991c6a44287SMartin K. Petersen 		break;
3992c6a44287SMartin K. Petersen 
3993c6a44287SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
3994c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE2_PROTECTION;
3995c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
3996c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE2_PROTECTION;
3997c6a44287SMartin K. Petersen 		break;
3998c6a44287SMartin K. Petersen 
3999c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
4000c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE3_PROTECTION;
4001c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
4002c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE3_PROTECTION;
4003c6a44287SMartin K. Petersen 		break;
4004c6a44287SMartin K. Petersen 
4005c6a44287SMartin K. Petersen 	default:
4006c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
4007c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE0_PROTECTION;
4008c6a44287SMartin K. Petersen 		break;
4009c6a44287SMartin K. Petersen 	}
4010c6a44287SMartin K. Petersen 
4011c6a44287SMartin K. Petersen 	scsi_host_set_prot(hpnt, host_prot);
4012c6a44287SMartin K. Petersen 
4013c6a44287SMartin K. Petersen 	printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
4014c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
4015c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
4016c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
4017c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
4018c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
4019c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
4020c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
4021c6a44287SMartin K. Petersen 
4022c6a44287SMartin K. Petersen 	if (scsi_debug_guard == 1)
4023c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
4024c6a44287SMartin K. Petersen 	else
4025c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
4026c6a44287SMartin K. Petersen 
40271da177e4SLinus Torvalds         error = scsi_add_host(hpnt, &sdbg_host->dev);
40281da177e4SLinus Torvalds         if (error) {
4029cadbd4a5SHarvey Harrison                 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
40301da177e4SLinus Torvalds                 error = -ENODEV;
40311da177e4SLinus Torvalds 		scsi_host_put(hpnt);
40321da177e4SLinus Torvalds         } else
40331da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
40341da177e4SLinus Torvalds 
40351da177e4SLinus Torvalds 
40361da177e4SLinus Torvalds         return error;
40371da177e4SLinus Torvalds }
40381da177e4SLinus Torvalds 
40391da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev)
40401da177e4SLinus Torvalds {
40411da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
40428b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
40431da177e4SLinus Torvalds 
40441da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
40451da177e4SLinus Torvalds 
40461da177e4SLinus Torvalds 	if (!sdbg_host) {
40471da177e4SLinus Torvalds 		printk(KERN_ERR "%s: Unable to locate host info\n",
4048cadbd4a5SHarvey Harrison 		       __func__);
40491da177e4SLinus Torvalds 		return -ENODEV;
40501da177e4SLinus Torvalds 	}
40511da177e4SLinus Torvalds 
40521da177e4SLinus Torvalds         scsi_remove_host(sdbg_host->shost);
40531da177e4SLinus Torvalds 
40548b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
40558b40228fSFUJITA Tomonori 				 dev_list) {
40561da177e4SLinus Torvalds                 list_del(&sdbg_devinfo->dev_list);
40571da177e4SLinus Torvalds                 kfree(sdbg_devinfo);
40581da177e4SLinus Torvalds         }
40591da177e4SLinus Torvalds 
40601da177e4SLinus Torvalds         scsi_host_put(sdbg_host->shost);
40611da177e4SLinus Torvalds         return 0;
40621da177e4SLinus Torvalds }
40631da177e4SLinus Torvalds 
40648dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
40658dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
40661da177e4SLinus Torvalds {
40678dea0d02SFUJITA Tomonori 	return 1;
40688dea0d02SFUJITA Tomonori }
40691da177e4SLinus Torvalds 
40708dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
40718dea0d02SFUJITA Tomonori 	.name = "pseudo",
40728dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
40738dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
40748dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
407582069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
40768dea0d02SFUJITA Tomonori };
4077