xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision a027b5b9)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
31da177e4SLinus Torvalds  *  Copyright (C) 1992  Eric Youngdale
41da177e4SLinus Torvalds  *  Simulate a host adapter with 2 disks attached.  Do a lot of checking
51da177e4SLinus Torvalds  *  to make sure that we are not getting blocks mixed up, and PANIC if
61da177e4SLinus Torvalds  *  anything out of the ordinary is seen.
71da177e4SLinus Torvalds  * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *  This version is more generic, simulating a variable number of disk
1023183910SDouglas Gilbert  *  (or disk like devices) sharing a common amount of RAM. To be more
1123183910SDouglas Gilbert  *  realistic, the simulated devices have the transport attributes of
1223183910SDouglas Gilbert  *  SAS disks.
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  *
1578d4e5a0SDouglas Gilbert  *  For documentation see http://sg.danny.cz/sg/sdebug26.html
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  *   D. Gilbert (dpg) work for Magneto-Optical device test [20010421]
181da177e4SLinus Torvalds  *   dpg: work for devfs large number of disks [20010809]
191da177e4SLinus Torvalds  *        forked for lk 2.5 series [20011216, 20020101]
201da177e4SLinus Torvalds  *        use vmalloc() more inquiry+mode_sense [20020302]
211da177e4SLinus Torvalds  *        add timers for delayed responses [20020721]
221da177e4SLinus Torvalds  *   Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031]
231da177e4SLinus Torvalds  *   Mike Anderson <andmike@us.ibm.com> sysfs work [20021118]
241da177e4SLinus Torvalds  *   dpg: change style of boot options to "scsi_debug.num_tgts=2" and
251da177e4SLinus Torvalds  *        module options to "modprobe scsi_debug num_tgts=2" [20021221]
261da177e4SLinus Torvalds  */
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds #include <linux/module.h>
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds #include <linux/kernel.h>
311da177e4SLinus Torvalds #include <linux/errno.h>
321da177e4SLinus Torvalds #include <linux/timer.h>
335a0e3ad6STejun Heo #include <linux/slab.h>
341da177e4SLinus Torvalds #include <linux/types.h>
351da177e4SLinus Torvalds #include <linux/string.h>
361da177e4SLinus Torvalds #include <linux/genhd.h>
371da177e4SLinus Torvalds #include <linux/fs.h>
381da177e4SLinus Torvalds #include <linux/init.h>
391da177e4SLinus Torvalds #include <linux/proc_fs.h>
401da177e4SLinus Torvalds #include <linux/vmalloc.h>
411da177e4SLinus Torvalds #include <linux/moduleparam.h>
42852e034dSJens Axboe #include <linux/scatterlist.h>
431da177e4SLinus Torvalds #include <linux/blkdev.h>
44c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h>
45c6a44287SMartin K. Petersen 
46c6a44287SMartin K. Petersen #include <net/checksum.h>
479ff26eefSFUJITA Tomonori 
4844d92694SMartin K. Petersen #include <asm/unaligned.h>
4944d92694SMartin K. Petersen 
509ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
519ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
529ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
531da177e4SLinus Torvalds #include <scsi/scsi_host.h>
541da177e4SLinus Torvalds #include <scsi/scsicam.h>
55a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
56395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
571da177e4SLinus Torvalds 
58c6a44287SMartin K. Petersen #include "sd.h"
591da177e4SLinus Torvalds #include "scsi_logging.h"
601da177e4SLinus Torvalds 
6178d4e5a0SDouglas Gilbert #define SCSI_DEBUG_VERSION "1.82"
6278d4e5a0SDouglas Gilbert static const char * scsi_debug_version_date = "20100324";
631da177e4SLinus Torvalds 
646f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
65c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
66c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
671da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
68c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
691da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
701da177e4SLinus Torvalds #define ADDR_OUT_OF_RANGE 0x21
71395cef03SMartin K. Petersen #define INVALID_COMMAND_OPCODE 0x20
721da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
73c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
741da177e4SLinus Torvalds #define POWERON_RESET 0x29
751da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
766f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
77c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
78c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
791da177e4SLinus Torvalds 
806f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
816f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
826f3cbf55SDouglas Gilbert 
831da177e4SLinus Torvalds #define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds /* Default values for driver parameters */
861da177e4SLinus Torvalds #define DEF_NUM_HOST   1
871da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
881da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
891da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
901da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
911da177e4SLinus Torvalds  */
925b94e232SMartin K. Petersen #define DEF_ATO 1
931da177e4SLinus Torvalds #define DEF_DELAY   1
941da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
955b94e232SMartin K. Petersen #define DEF_DIF 0
965b94e232SMartin K. Petersen #define DEF_DIX 0
975b94e232SMartin K. Petersen #define DEF_D_SENSE   0
981da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
995b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1005b94e232SMartin K. Petersen #define DEF_GUARD 0
1015b94e232SMartin K. Petersen #define DEF_LBPU 0
1025b94e232SMartin K. Petersen #define DEF_LBPWS 0
1035b94e232SMartin K. Petersen #define DEF_LBPWS10 0
104be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1055b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
1065b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1071da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1081da177e4SLinus Torvalds #define DEF_OPTS   0
109e308b3d1SMartin K. Petersen #define DEF_OPT_BLKS 64
1105b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
1115b94e232SMartin K. Petersen #define DEF_PTYPE   0
112d986788bSMartin Pitt #define DEF_REMOVABLE false
1135b94e232SMartin K. Petersen #define DEF_SCSI_LEVEL   5    /* INQUIRY, byte2 [5->SPC-3] */
1145b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1155b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1165b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1176014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1186014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1195b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1205b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1215b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
1221da177e4SLinus Torvalds 
1231da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */
1241da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE   1
1251da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR   2
1261da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT   4
1271da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR   8
1286f3cbf55SDouglas Gilbert #define SCSI_DEBUG_OPT_TRANSPORT_ERR   16
129c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIF_ERR   32
130c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIX_ERR   64
13118a4d0a2SMartin K. Petersen #define SCSI_DEBUG_OPT_MAC_TIMEOUT  128
1321da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
1331da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1341da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1351da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1366f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1376f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1381da177e4SLinus Torvalds  *
1391da177e4SLinus Torvalds  * When "every_nth" < 0 then after "- every_nth" commands:
1401da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1411da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1421da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1436f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1446f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1451da177e4SLinus Torvalds  * This will continue until some other action occurs (e.g. the user
1461da177e4SLinus Torvalds  * writing a new value (other than -1 or 1) to every_nth via sysfs).
1471da177e4SLinus Torvalds  */
1481da177e4SLinus Torvalds 
1491da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
1501da177e4SLinus Torvalds  * sector on read commands: */
1511da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
15232f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
1551da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
1561da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
157c65b1445SDouglas Gilbert #define SAM2_WLUN_REPORT_LUNS 0xc101
1581da177e4SLinus Torvalds 
15978d4e5a0SDouglas Gilbert /* Can queue up to this number of commands. Typically commands that
16078d4e5a0SDouglas Gilbert  * that have a non-zero delay are queued. */
16178d4e5a0SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE  255
16278d4e5a0SDouglas Gilbert 
1631da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST;
1645b94e232SMartin K. Petersen static int scsi_debug_ato = DEF_ATO;
1651da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY;
1661da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
1675b94e232SMartin K. Petersen static int scsi_debug_dif = DEF_DIF;
1685b94e232SMartin K. Petersen static int scsi_debug_dix = DEF_DIX;
1695b94e232SMartin K. Petersen static int scsi_debug_dsense = DEF_D_SENSE;
1701da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH;
1715b94e232SMartin K. Petersen static int scsi_debug_fake_rw = DEF_FAKE_RW;
1725b94e232SMartin K. Petersen static int scsi_debug_guard = DEF_GUARD;
1735b94e232SMartin K. Petersen static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
1741da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS;
17578d4e5a0SDouglas Gilbert static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE;
176c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
1775b94e232SMartin K. Petersen static int scsi_debug_no_uld = 0;
1785b94e232SMartin K. Petersen static int scsi_debug_num_parts = DEF_NUM_PARTS;
1795b94e232SMartin K. Petersen static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
180e308b3d1SMartin K. Petersen static int scsi_debug_opt_blks = DEF_OPT_BLKS;
1815b94e232SMartin K. Petersen static int scsi_debug_opts = DEF_OPTS;
1825b94e232SMartin K. Petersen static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
1835b94e232SMartin K. Petersen static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
1845b94e232SMartin K. Petersen static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
1855b94e232SMartin K. Petersen static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
1865b94e232SMartin K. Petersen static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
1875b94e232SMartin K. Petersen static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
1885b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpu = DEF_LBPU;
1895b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws = DEF_LBPWS;
1905b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10;
191be1dd78dSEric Sandeen static unsigned int scsi_debug_lbprz = DEF_LBPRZ;
1926014759cSMartin K. Petersen static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
1935b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
1945b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
1955b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
1965b94e232SMartin K. Petersen static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH;
197d986788bSMartin Pitt static bool scsi_debug_removable = DEF_REMOVABLE;
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds static int scsi_debug_cmnd_count = 0;
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds #define DEV_READONLY(TGT)      (0)
2021da177e4SLinus Torvalds 
203c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
2041da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
2051da177e4SLinus Torvalds 
2061da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
2071da177e4SLinus Torvalds    may still need them */
2081da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
2091da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
2101da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4
2131da177e4SLinus Torvalds 
2141da177e4SLinus Torvalds #define SDEBUG_SENSE_LEN 32
2151da177e4SLinus Torvalds 
216395cef03SMartin K. Petersen #define SCSI_DEBUG_MAX_CMD_LEN 32
2179e603ca0SFUJITA Tomonori 
2185b94e232SMartin K. Petersen static unsigned int scsi_debug_lbp(void)
2195b94e232SMartin K. Petersen {
2205b94e232SMartin K. Petersen 	return scsi_debug_lbpu | scsi_debug_lbpws | scsi_debug_lbpws10;
2215b94e232SMartin K. Petersen }
2225b94e232SMartin K. Petersen 
2231da177e4SLinus Torvalds struct sdebug_dev_info {
2241da177e4SLinus Torvalds 	struct list_head dev_list;
2251da177e4SLinus Torvalds 	unsigned char sense_buff[SDEBUG_SENSE_LEN];	/* weak nexus */
2261da177e4SLinus Torvalds 	unsigned int channel;
2271da177e4SLinus Torvalds 	unsigned int target;
2281da177e4SLinus Torvalds 	unsigned int lun;
2291da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
230c65b1445SDouglas Gilbert 	unsigned int wlun;
2311da177e4SLinus Torvalds 	char reset;
232c65b1445SDouglas Gilbert 	char stopped;
2331da177e4SLinus Torvalds 	char used;
2341da177e4SLinus Torvalds };
2351da177e4SLinus Torvalds 
2361da177e4SLinus Torvalds struct sdebug_host_info {
2371da177e4SLinus Torvalds 	struct list_head host_list;
2381da177e4SLinus Torvalds 	struct Scsi_Host *shost;
2391da177e4SLinus Torvalds 	struct device dev;
2401da177e4SLinus Torvalds 	struct list_head dev_info_list;
2411da177e4SLinus Torvalds };
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds #define to_sdebug_host(d)	\
2441da177e4SLinus Torvalds 	container_of(d, struct sdebug_host_info, dev)
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
2471da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds typedef void (* done_funct_t) (struct scsi_cmnd *);
2501da177e4SLinus Torvalds 
2511da177e4SLinus Torvalds struct sdebug_queued_cmd {
2521da177e4SLinus Torvalds 	int in_use;
2531da177e4SLinus Torvalds 	struct timer_list cmnd_timer;
2541da177e4SLinus Torvalds 	done_funct_t done_funct;
2551da177e4SLinus Torvalds 	struct scsi_cmnd * a_cmnd;
2561da177e4SLinus Torvalds 	int scsi_result;
2571da177e4SLinus Torvalds };
2581da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
2591da177e4SLinus Torvalds 
2601da177e4SLinus Torvalds static unsigned char * fake_storep;	/* ramdisk storage */
261e18d8beaSAkinobu Mita static struct sd_dif_tuple *dif_storep;	/* protection info */
26244d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
2631da177e4SLinus Torvalds 
26444d92694SMartin K. Petersen static unsigned long map_size;
2651da177e4SLinus Torvalds static int num_aborts = 0;
2661da177e4SLinus Torvalds static int num_dev_resets = 0;
2671da177e4SLinus Torvalds static int num_bus_resets = 0;
2681da177e4SLinus Torvalds static int num_host_resets = 0;
269c6a44287SMartin K. Petersen static int dix_writes;
270c6a44287SMartin K. Petersen static int dix_reads;
271c6a44287SMartin K. Petersen static int dif_errors;
2721da177e4SLinus Torvalds 
2731da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock);
2741da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds static char sdebug_proc_name[] = "scsi_debug";
2771da177e4SLinus Torvalds 
2781da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
2791da177e4SLinus Torvalds 
2801da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
2811da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
2821da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
2831da177e4SLinus Torvalds };
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds static const int check_condition_result =
2861da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
2871da177e4SLinus Torvalds 
288c6a44287SMartin K. Petersen static const int illegal_condition_result =
289c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
290c6a44287SMartin K. Petersen 
291c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
292c65b1445SDouglas Gilbert 				    0, 0, 0x2, 0x4b};
293c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
294c65b1445SDouglas Gilbert 			           0, 0, 0x0, 0x0};
295c65b1445SDouglas Gilbert 
2961da177e4SLinus Torvalds static int sdebug_add_adapter(void);
2971da177e4SLinus Torvalds static void sdebug_remove_adapter(void);
2981da177e4SLinus Torvalds 
2998dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
3008dea0d02SFUJITA Tomonori {
3018dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
3028dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
3038dea0d02SFUJITA Tomonori 
3048dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
3058dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3068dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
3078dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
3088dea0d02SFUJITA Tomonori 		    (scsi_debug_num_tgts > hpnt->this_id))
3098dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts + 1;
3108dea0d02SFUJITA Tomonori 		else
3118dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts;
3128dea0d02SFUJITA Tomonori 		/* scsi_debug_max_luns; */
3138dea0d02SFUJITA Tomonori 		hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
3148dea0d02SFUJITA Tomonori 	}
3158dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
3168dea0d02SFUJITA Tomonori }
3178dea0d02SFUJITA Tomonori 
3188dea0d02SFUJITA Tomonori static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
3198dea0d02SFUJITA Tomonori 			    int asc, int asq)
3208dea0d02SFUJITA Tomonori {
3218dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
3228dea0d02SFUJITA Tomonori 
3238dea0d02SFUJITA Tomonori 	sbuff = devip->sense_buff;
3248dea0d02SFUJITA Tomonori 	memset(sbuff, 0, SDEBUG_SENSE_LEN);
3258dea0d02SFUJITA Tomonori 
3268dea0d02SFUJITA Tomonori 	scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
3278dea0d02SFUJITA Tomonori 
3288dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3298dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug:    [sense_key,asc,ascq]: "
3308dea0d02SFUJITA Tomonori 		      "[0x%x,0x%x,0x%x]\n", key, asc, asq);
3318dea0d02SFUJITA Tomonori }
3321da177e4SLinus Torvalds 
3333de9f944SFUJITA Tomonori static void get_data_transfer_info(unsigned char *cmd,
334395cef03SMartin K. Petersen 				   unsigned long long *lba, unsigned int *num,
335395cef03SMartin K. Petersen 				   u32 *ei_lba)
3363de9f944SFUJITA Tomonori {
337395cef03SMartin K. Petersen 	*ei_lba = 0;
338395cef03SMartin K. Petersen 
3393de9f944SFUJITA Tomonori 	switch (*cmd) {
340395cef03SMartin K. Petersen 	case VARIABLE_LENGTH_CMD:
341395cef03SMartin K. Petersen 		*lba = (u64)cmd[19] | (u64)cmd[18] << 8 |
342395cef03SMartin K. Petersen 			(u64)cmd[17] << 16 | (u64)cmd[16] << 24 |
343395cef03SMartin K. Petersen 			(u64)cmd[15] << 32 | (u64)cmd[14] << 40 |
344395cef03SMartin K. Petersen 			(u64)cmd[13] << 48 | (u64)cmd[12] << 56;
345395cef03SMartin K. Petersen 
346395cef03SMartin K. Petersen 		*ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 |
347395cef03SMartin K. Petersen 			(u32)cmd[21] << 16 | (u32)cmd[20] << 24;
348395cef03SMartin K. Petersen 
349395cef03SMartin K. Petersen 		*num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 |
350395cef03SMartin K. Petersen 			(u32)cmd[28] << 24;
351395cef03SMartin K. Petersen 		break;
352395cef03SMartin K. Petersen 
35344d92694SMartin K. Petersen 	case WRITE_SAME_16:
3543de9f944SFUJITA Tomonori 	case WRITE_16:
3553de9f944SFUJITA Tomonori 	case READ_16:
356d5cdc989SFUJITA Tomonori 		*lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
357d5cdc989SFUJITA Tomonori 			(u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
358d5cdc989SFUJITA Tomonori 			(u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
359d5cdc989SFUJITA Tomonori 			(u64)cmd[3] << 48 | (u64)cmd[2] << 56;
360d5cdc989SFUJITA Tomonori 
361d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
362d5cdc989SFUJITA Tomonori 			(u32)cmd[10] << 24;
3633de9f944SFUJITA Tomonori 		break;
3643de9f944SFUJITA Tomonori 	case WRITE_12:
3653de9f944SFUJITA Tomonori 	case READ_12:
366d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
367d5cdc989SFUJITA Tomonori 			(u32)cmd[2] << 24;
368d5cdc989SFUJITA Tomonori 
369d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
370d5cdc989SFUJITA Tomonori 			(u32)cmd[6] << 24;
3713de9f944SFUJITA Tomonori 		break;
37244d92694SMartin K. Petersen 	case WRITE_SAME:
3733de9f944SFUJITA Tomonori 	case WRITE_10:
3743de9f944SFUJITA Tomonori 	case READ_10:
375c639d14eSFUJITA Tomonori 	case XDWRITEREAD_10:
376d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[5] | (u32)cmd[4] << 8 |	(u32)cmd[3] << 16 |
377d5cdc989SFUJITA Tomonori 			(u32)cmd[2] << 24;
378d5cdc989SFUJITA Tomonori 
379d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[8] | (u32)cmd[7] << 8;
3803de9f944SFUJITA Tomonori 		break;
3813de9f944SFUJITA Tomonori 	case WRITE_6:
3823de9f944SFUJITA Tomonori 	case READ_6:
383d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
384d5cdc989SFUJITA Tomonori 			(u32)(cmd[1] & 0x1f) << 16;
3853de9f944SFUJITA Tomonori 		*num = (0 == cmd[4]) ? 256 : cmd[4];
3863de9f944SFUJITA Tomonori 		break;
3873de9f944SFUJITA Tomonori 	default:
3883de9f944SFUJITA Tomonori 		break;
3893de9f944SFUJITA Tomonori 	}
3903de9f944SFUJITA Tomonori }
3911da177e4SLinus Torvalds 
3921da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
3931da177e4SLinus Torvalds {
3941da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
3951da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
3961da177e4SLinus Torvalds 	}
3971da177e4SLinus Torvalds 	return -EINVAL;
3981da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
3991da177e4SLinus Torvalds }
4001da177e4SLinus Torvalds 
401c65b1445SDouglas Gilbert static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
402c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
4031da177e4SLinus Torvalds {
4041da177e4SLinus Torvalds 	if (devip->reset) {
4051da177e4SLinus Torvalds 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
4061da177e4SLinus Torvalds 			printk(KERN_INFO "scsi_debug: Reporting Unit "
4071da177e4SLinus Torvalds 			       "attention: power on reset\n");
4081da177e4SLinus Torvalds 		devip->reset = 0;
4091da177e4SLinus Torvalds 		mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
4101da177e4SLinus Torvalds 		return check_condition_result;
4111da177e4SLinus Torvalds 	}
412c65b1445SDouglas Gilbert 	if ((0 == reset_only) && devip->stopped) {
413c65b1445SDouglas Gilbert 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
414c65b1445SDouglas Gilbert 			printk(KERN_INFO "scsi_debug: Reporting Not "
415c65b1445SDouglas Gilbert 			       "ready: initializing command required\n");
416c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
417c65b1445SDouglas Gilbert 				0x2);
418c65b1445SDouglas Gilbert 		return check_condition_result;
419c65b1445SDouglas Gilbert 	}
4201da177e4SLinus Torvalds 	return 0;
4211da177e4SLinus Torvalds }
4221da177e4SLinus Torvalds 
4231da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
4241da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
4251da177e4SLinus Torvalds 				int arr_len)
4261da177e4SLinus Torvalds {
42721a61829SFUJITA Tomonori 	int act_len;
428072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
4291da177e4SLinus Torvalds 
430072d0bb3SFUJITA Tomonori 	if (!sdb->length)
4311da177e4SLinus Torvalds 		return 0;
432072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
4331da177e4SLinus Torvalds 		return (DID_ERROR << 16);
43421a61829SFUJITA Tomonori 
43521a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
43621a61829SFUJITA Tomonori 				      arr, arr_len);
43721a61829SFUJITA Tomonori 	sdb->resid = scsi_bufflen(scp) - act_len;
43821a61829SFUJITA Tomonori 
4391da177e4SLinus Torvalds 	return 0;
4401da177e4SLinus Torvalds }
4411da177e4SLinus Torvalds 
4421da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */
4431da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
44421a61829SFUJITA Tomonori 			       int arr_len)
4451da177e4SLinus Torvalds {
44621a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
4471da177e4SLinus Torvalds 		return 0;
448072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
4491da177e4SLinus Torvalds 		return -1;
45021a61829SFUJITA Tomonori 
45121a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
4521da177e4SLinus Torvalds }
4531da177e4SLinus Torvalds 
4541da177e4SLinus Torvalds 
4551da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux   ";
4561da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug      ";
4571da177e4SLinus Torvalds static const char * inq_product_rev = "0004";
4581da177e4SLinus Torvalds 
4595a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
4605a09e398SHannes Reinecke 			   int target_dev_id, int dev_id_num,
4615a09e398SHannes Reinecke 			   const char * dev_id_str,
462c65b1445SDouglas Gilbert 			   int dev_id_str_len)
4631da177e4SLinus Torvalds {
464c65b1445SDouglas Gilbert 	int num, port_a;
465c65b1445SDouglas Gilbert 	char b[32];
4661da177e4SLinus Torvalds 
467c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
4681da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
4691da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
4701da177e4SLinus Torvalds 	arr[1] = 0x1;
4711da177e4SLinus Torvalds 	arr[2] = 0x0;
4721da177e4SLinus Torvalds 	memcpy(&arr[4], inq_vendor_id, 8);
4731da177e4SLinus Torvalds 	memcpy(&arr[12], inq_product_id, 16);
4741da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
4751da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
4761da177e4SLinus Torvalds 	arr[3] = num;
4771da177e4SLinus Torvalds 	num += 4;
478c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
479c65b1445SDouglas Gilbert 		/* NAA-5, Logical unit identifier (binary) */
480c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* binary (not necessarily sas) */
481c65b1445SDouglas Gilbert 		arr[num++] = 0x3;	/* PIV=0, lu, naa */
482c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
483c65b1445SDouglas Gilbert 		arr[num++] = 0x8;
484c65b1445SDouglas Gilbert 		arr[num++] = 0x53;  /* naa-5 ieee company id=0x333333 (fake) */
485c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
486c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
487c65b1445SDouglas Gilbert 		arr[num++] = 0x30;
488c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 24);
489c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 16) & 0xff;
490c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 8) & 0xff;
491c65b1445SDouglas Gilbert 		arr[num++] = dev_id_num & 0xff;
492c65b1445SDouglas Gilbert 		/* Target relative port number */
493c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
494c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
495c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
496c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
497c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
498c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
499c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
500c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
501c65b1445SDouglas Gilbert 	}
502c65b1445SDouglas Gilbert 	/* NAA-5, Target port identifier */
503c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
504c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
505c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
506c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
507c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
508c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
509c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
510c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
511c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
512c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
513c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
514c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
5155a09e398SHannes Reinecke 	/* NAA-5, Target port group identifier */
5165a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
5175a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
5185a09e398SHannes Reinecke 	arr[num++] = 0x0;
5195a09e398SHannes Reinecke 	arr[num++] = 0x4;
5205a09e398SHannes Reinecke 	arr[num++] = 0;
5215a09e398SHannes Reinecke 	arr[num++] = 0;
5225a09e398SHannes Reinecke 	arr[num++] = (port_group_id >> 8) & 0xff;
5235a09e398SHannes Reinecke 	arr[num++] = port_group_id & 0xff;
524c65b1445SDouglas Gilbert 	/* NAA-5, Target device identifier */
525c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
526c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
527c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
528c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
529c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
530c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
531c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
532c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
533c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 24);
534c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 16) & 0xff;
535c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 8) & 0xff;
536c65b1445SDouglas Gilbert 	arr[num++] = target_dev_id & 0xff;
537c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
538c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
539c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
540c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
541c65b1445SDouglas Gilbert 	arr[num++] = 24;
542c65b1445SDouglas Gilbert 	memcpy(arr + num, "naa.52222220", 12);
543c65b1445SDouglas Gilbert 	num += 12;
544c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
545c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
546c65b1445SDouglas Gilbert 	num += 8;
547c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
548c65b1445SDouglas Gilbert 	num += 4;
549c65b1445SDouglas Gilbert 	return num;
550c65b1445SDouglas Gilbert }
551c65b1445SDouglas Gilbert 
552c65b1445SDouglas Gilbert 
553c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
554c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
555c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
556c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
557c65b1445SDouglas Gilbert };
558c65b1445SDouglas Gilbert 
559c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr)
560c65b1445SDouglas Gilbert {
561c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
562c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
563c65b1445SDouglas Gilbert }
564c65b1445SDouglas Gilbert 
565c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr)
566c65b1445SDouglas Gilbert {
567c65b1445SDouglas Gilbert 	int num = 0;
568c65b1445SDouglas Gilbert 	const char * na1 = "https://www.kernel.org/config";
569c65b1445SDouglas Gilbert 	const char * na2 = "http://www.kernel.org/log";
570c65b1445SDouglas Gilbert 	int plen, olen;
571c65b1445SDouglas Gilbert 
572c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
573c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
574c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
575c65b1445SDouglas Gilbert 	olen = strlen(na1);
576c65b1445SDouglas Gilbert 	plen = olen + 1;
577c65b1445SDouglas Gilbert 	if (plen % 4)
578c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
579c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
580c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
581c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
582c65b1445SDouglas Gilbert 	num += plen;
583c65b1445SDouglas Gilbert 
584c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
585c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
586c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
587c65b1445SDouglas Gilbert 	olen = strlen(na2);
588c65b1445SDouglas Gilbert 	plen = olen + 1;
589c65b1445SDouglas Gilbert 	if (plen % 4)
590c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
591c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
592c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
593c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
594c65b1445SDouglas Gilbert 	num += plen;
595c65b1445SDouglas Gilbert 
596c65b1445SDouglas Gilbert 	return num;
597c65b1445SDouglas Gilbert }
598c65b1445SDouglas Gilbert 
599c65b1445SDouglas Gilbert /* SCSI ports VPD page */
600c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
601c65b1445SDouglas Gilbert {
602c65b1445SDouglas Gilbert 	int num = 0;
603c65b1445SDouglas Gilbert 	int port_a, port_b;
604c65b1445SDouglas Gilbert 
605c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
606c65b1445SDouglas Gilbert 	port_b = port_a + 1;
607c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
608c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
609c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
610c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
611c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
612c65b1445SDouglas Gilbert 	num += 6;
613c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
614c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
615c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
616c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
617c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
618c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
619c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
620c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
621c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
622c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
623c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
624c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
625c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
626c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
627c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
628c65b1445SDouglas Gilbert 
629c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
630c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
631c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
632c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
633c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
634c65b1445SDouglas Gilbert 	num += 6;
635c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
636c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
637c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
638c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
639c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
640c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
641c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
642c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
643c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
644c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
645c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
646c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 24);
647c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 16) & 0xff;
648c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 8) & 0xff;
649c65b1445SDouglas Gilbert 	arr[num++] = port_b & 0xff;
650c65b1445SDouglas Gilbert 
651c65b1445SDouglas Gilbert 	return num;
652c65b1445SDouglas Gilbert }
653c65b1445SDouglas Gilbert 
654c65b1445SDouglas Gilbert 
655c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
656c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
657c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
658c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
659c65b1445SDouglas Gilbert '1','2','3','4',
660c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
661c65b1445SDouglas Gilbert 0xec,0,0,0,
662c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
663c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
664c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
665c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
666c65b1445SDouglas Gilbert 0x53,0x41,
667c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
668c65b1445SDouglas Gilbert 0x20,0x20,
669c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
670c65b1445SDouglas Gilbert 0x10,0x80,
671c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
672c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
673c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
674c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
675c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
676c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
677c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
678c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
679c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
680c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
681c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
682c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
683c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
684c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
685c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
686c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
687c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
688c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
689c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
690c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
691c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
692c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
693c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
694c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
695c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
696c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
697c65b1445SDouglas Gilbert };
698c65b1445SDouglas Gilbert 
699c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr)
700c65b1445SDouglas Gilbert {
701c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
702c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
703c65b1445SDouglas Gilbert }
704c65b1445SDouglas Gilbert 
705c65b1445SDouglas Gilbert 
7061e49f785SDouglas Gilbert /* Block limits VPD page (SBC-3) */
707c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
7081e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
7091e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7101e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7111e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
712c65b1445SDouglas Gilbert };
713c65b1445SDouglas Gilbert 
714c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr)
715c65b1445SDouglas Gilbert {
716ea61fca5SMartin K. Petersen 	unsigned int gran;
717ea61fca5SMartin K. Petersen 
718c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
719e308b3d1SMartin K. Petersen 
720e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
721ea61fca5SMartin K. Petersen 	gran = 1 << scsi_debug_physblk_exp;
722ea61fca5SMartin K. Petersen 	arr[2] = (gran >> 8) & 0xff;
723ea61fca5SMartin K. Petersen 	arr[3] = gran & 0xff;
724e308b3d1SMartin K. Petersen 
725e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
726c65b1445SDouglas Gilbert 	if (sdebug_store_sectors > 0x400) {
727c65b1445SDouglas Gilbert 		arr[4] = (sdebug_store_sectors >> 24) & 0xff;
728c65b1445SDouglas Gilbert 		arr[5] = (sdebug_store_sectors >> 16) & 0xff;
729c65b1445SDouglas Gilbert 		arr[6] = (sdebug_store_sectors >> 8) & 0xff;
730c65b1445SDouglas Gilbert 		arr[7] = sdebug_store_sectors & 0xff;
731c65b1445SDouglas Gilbert 	}
73244d92694SMartin K. Petersen 
733e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
734e308b3d1SMartin K. Petersen 	put_unaligned_be32(scsi_debug_opt_blks, &arr[8]);
735e308b3d1SMartin K. Petersen 
7365b94e232SMartin K. Petersen 	if (scsi_debug_lbpu) {
737e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
7386014759cSMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]);
739e308b3d1SMartin K. Petersen 
740e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
74144d92694SMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
74244d92694SMartin K. Petersen 	}
74344d92694SMartin K. Petersen 
744e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
74544d92694SMartin K. Petersen 	if (scsi_debug_unmap_alignment) {
74644d92694SMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
74744d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
74844d92694SMartin K. Petersen 	}
74944d92694SMartin K. Petersen 
750e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
75144d92694SMartin K. Petersen 	put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
7526014759cSMartin K. Petersen 
7535b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
7545b94e232SMartin K. Petersen 	put_unaligned_be64(scsi_debug_write_same_length, &arr[32]);
7555b94e232SMartin K. Petersen 
7565b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
75744d92694SMartin K. Petersen 
758c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
7591da177e4SLinus Torvalds }
7601da177e4SLinus Torvalds 
7611e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
762eac6e8e4SMatthew Wilcox static int inquiry_evpd_b1(unsigned char *arr)
763eac6e8e4SMatthew Wilcox {
764eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
765eac6e8e4SMatthew Wilcox 	arr[0] = 0;
7661e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
7671e49f785SDouglas Gilbert 	arr[2] = 0;
7681e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
769eac6e8e4SMatthew Wilcox 
770eac6e8e4SMatthew Wilcox 	return 0x3c;
771eac6e8e4SMatthew Wilcox }
7721da177e4SLinus Torvalds 
773be1dd78dSEric Sandeen /* Logical block provisioning VPD page (SBC-3) */
7746014759cSMartin K. Petersen static int inquiry_evpd_b2(unsigned char *arr)
7756014759cSMartin K. Petersen {
7763f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
7776014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
7786014759cSMartin K. Petersen 
7795b94e232SMartin K. Petersen 	if (scsi_debug_lbpu)
7806014759cSMartin K. Petersen 		arr[1] = 1 << 7;
7816014759cSMartin K. Petersen 
7825b94e232SMartin K. Petersen 	if (scsi_debug_lbpws)
7836014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
7846014759cSMartin K. Petersen 
7855b94e232SMartin K. Petersen 	if (scsi_debug_lbpws10)
7865b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
7875b94e232SMartin K. Petersen 
788be1dd78dSEric Sandeen 	if (scsi_debug_lbprz)
789be1dd78dSEric Sandeen 		arr[1] |= 1 << 2;
790be1dd78dSEric Sandeen 
7913f0bc3b3SMartin K. Petersen 	return 0x4;
7926014759cSMartin K. Petersen }
7936014759cSMartin K. Petersen 
7941da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
795c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
7961da177e4SLinus Torvalds 
7971da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd * scp, int target,
7981da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
7991da177e4SLinus Torvalds {
8001da177e4SLinus Torvalds 	unsigned char pq_pdt;
8015a09e398SHannes Reinecke 	unsigned char * arr;
8021da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
8035a09e398SHannes Reinecke 	int alloc_len, n, ret;
8041da177e4SLinus Torvalds 
8051da177e4SLinus Torvalds 	alloc_len = (cmd[3] << 8) + cmd[4];
8066f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
8076f3cbf55SDouglas Gilbert 	if (! arr)
8086f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
809c65b1445SDouglas Gilbert 	if (devip->wlun)
810c65b1445SDouglas Gilbert 		pq_pdt = 0x1e;	/* present, wlun */
811c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (0 == devip->lun))
812c65b1445SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, no device type */
813c65b1445SDouglas Gilbert 	else
8141da177e4SLinus Torvalds 		pq_pdt = (scsi_debug_ptype & 0x1f);
8151da177e4SLinus Torvalds 	arr[0] = pq_pdt;
8161da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
8171da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
8181da177e4SLinus Torvalds 			       	0);
8195a09e398SHannes Reinecke 		kfree(arr);
8201da177e4SLinus Torvalds 		return check_condition_result;
8211da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
8225a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
823c65b1445SDouglas Gilbert 		char lu_id_str[6];
824c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
8251da177e4SLinus Torvalds 
8265a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
8275a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
82823183910SDouglas Gilbert 		if (0 == scsi_debug_vpd_use_hostno)
82923183910SDouglas Gilbert 			host_no = 0;
830c65b1445SDouglas Gilbert 		lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
831c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
832c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
833c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
834c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
8351da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
836c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
837c65b1445SDouglas Gilbert 			n = 4;
838c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
839c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
840c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
841c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
842c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
843c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
844c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
845c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
846c65b1445SDouglas Gilbert 			arr[n++] = 0x89;  /* ATA information */
847c65b1445SDouglas Gilbert 			arr[n++] = 0xb0;  /* Block limits (SBC) */
848eac6e8e4SMatthew Wilcox 			arr[n++] = 0xb1;  /* Block characteristics (SBC) */
8495b94e232SMartin K. Petersen 			if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
8505b94e232SMartin K. Petersen 				arr[n++] = 0xb2;
851c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
8521da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
853c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
8541da177e4SLinus Torvalds 			arr[3] = len;
855c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
8561da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
857c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
8585a09e398SHannes Reinecke 			arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
8595a09e398SHannes Reinecke 						 target_dev_id, lu_id_num,
8605a09e398SHannes Reinecke 						 lu_id_str, len);
861c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
862c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
863c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_84(&arr[4]);
864c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
865c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
866c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_85(&arr[4]);
867c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
868c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
869c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
870c6a44287SMartin K. Petersen 			if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
871c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
872c6a44287SMartin K. Petersen 			else if (scsi_debug_dif)
873c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
874c6a44287SMartin K. Petersen 			else
875c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
876c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
877c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
878c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
879c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
880c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
881c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
882c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
883c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
884c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
885c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
886c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
887c65b1445SDouglas Gilbert 		} else if (0x89 == cmd[2]) { /* ATA information */
888c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
889c65b1445SDouglas Gilbert 			n = inquiry_evpd_89(&arr[4]);
890c65b1445SDouglas Gilbert 			arr[2] = (n >> 8);
891c65b1445SDouglas Gilbert 			arr[3] = (n & 0xff);
892c65b1445SDouglas Gilbert 		} else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
893c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
894c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_b0(&arr[4]);
895eac6e8e4SMatthew Wilcox 		} else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
896eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
897eac6e8e4SMatthew Wilcox 			arr[3] = inquiry_evpd_b1(&arr[4]);
8985b94e232SMartin K. Petersen 		} else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
8996014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
9006014759cSMartin K. Petersen 			arr[3] = inquiry_evpd_b2(&arr[4]);
9011da177e4SLinus Torvalds 		} else {
9021da177e4SLinus Torvalds 			/* Illegal request, invalid field in cdb */
9031da177e4SLinus Torvalds 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
9041da177e4SLinus Torvalds 					INVALID_FIELD_IN_CDB, 0);
9055a09e398SHannes Reinecke 			kfree(arr);
9061da177e4SLinus Torvalds 			return check_condition_result;
9071da177e4SLinus Torvalds 		}
908c65b1445SDouglas Gilbert 		len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
9095a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
910c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
9115a09e398SHannes Reinecke 		kfree(arr);
9125a09e398SHannes Reinecke 		return ret;
9131da177e4SLinus Torvalds 	}
9141da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
915d986788bSMartin Pitt 	arr[1] = scsi_debug_removable ? 0x80 : 0;	/* Removable disk */
9161da177e4SLinus Torvalds 	arr[2] = scsi_debug_scsi_level;
9171da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
9181da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
919c6a44287SMartin K. Petersen 	arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
9205a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno)
9215a09e398SHannes Reinecke 		arr[5] = 0x10; /* claim: implicit TGPS */
922c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
9231da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
924c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
9251da177e4SLinus Torvalds 	memcpy(&arr[8], inq_vendor_id, 8);
9261da177e4SLinus Torvalds 	memcpy(&arr[16], inq_product_id, 16);
9271da177e4SLinus Torvalds 	memcpy(&arr[32], inq_product_rev, 4);
9281da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
929c65b1445SDouglas Gilbert 	arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
930c65b1445SDouglas Gilbert 	arr[60] = 0x3; arr[61] = 0x14;  /* SPC-3 ANSI */
931c65b1445SDouglas Gilbert 	n = 62;
9321da177e4SLinus Torvalds 	if (scsi_debug_ptype == 0) {
933c65b1445SDouglas Gilbert 		arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
9341da177e4SLinus Torvalds 	} else if (scsi_debug_ptype == 1) {
935c65b1445SDouglas Gilbert 		arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
9361da177e4SLinus Torvalds 	}
937c65b1445SDouglas Gilbert 	arr[n++] = 0xc; arr[n++] = 0xf;  /* SAS-1.1 rev 10 */
9385a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
9391da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
9405a09e398SHannes Reinecke 	kfree(arr);
9415a09e398SHannes Reinecke 	return ret;
9421da177e4SLinus Torvalds }
9431da177e4SLinus Torvalds 
9441da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp,
9451da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip)
9461da177e4SLinus Torvalds {
9471da177e4SLinus Torvalds 	unsigned char * sbuff;
9481da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
9491da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_SENSE_LEN];
950c65b1445SDouglas Gilbert 	int want_dsense;
9511da177e4SLinus Torvalds 	int len = 18;
9521da177e4SLinus Torvalds 
953c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
9541da177e4SLinus Torvalds 	if (devip->reset == 1)
955c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
956c65b1445SDouglas Gilbert 	want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
9571da177e4SLinus Torvalds 	sbuff = devip->sense_buff;
958c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
959c65b1445SDouglas Gilbert 		if (want_dsense) {
960c65b1445SDouglas Gilbert 			arr[0] = 0x72;
961c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
962c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
963c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
964c65b1445SDouglas Gilbert 		} else {
965c65b1445SDouglas Gilbert 			arr[0] = 0x70;
966c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
967c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
968c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
969c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
970c65b1445SDouglas Gilbert 		}
971c65b1445SDouglas Gilbert 	} else {
972c65b1445SDouglas Gilbert 		memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
9731da177e4SLinus Torvalds 		if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
9741da177e4SLinus Torvalds 			/* DESC bit set and sense_buff in fixed format */
975c65b1445SDouglas Gilbert 			memset(arr, 0, sizeof(arr));
9761da177e4SLinus Torvalds 			arr[0] = 0x72;
9771da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
9781da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
9791da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
9801da177e4SLinus Torvalds 			len = 8;
981c65b1445SDouglas Gilbert 		}
982c65b1445SDouglas Gilbert 	}
983c65b1445SDouglas Gilbert 	mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
9841da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
9851da177e4SLinus Torvalds }
9861da177e4SLinus Torvalds 
987c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp,
988c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
989c65b1445SDouglas Gilbert {
990c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
991c65b1445SDouglas Gilbert 	int power_cond, errsts, start;
992c65b1445SDouglas Gilbert 
993c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
994c65b1445SDouglas Gilbert 		return errsts;
995c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
996c65b1445SDouglas Gilbert 	if (power_cond) {
997c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
998c65b1445SDouglas Gilbert 			       	0);
999c65b1445SDouglas Gilbert 		return check_condition_result;
1000c65b1445SDouglas Gilbert 	}
1001c65b1445SDouglas Gilbert 	start = cmd[4] & 1;
1002c65b1445SDouglas Gilbert 	if (start == devip->stopped)
1003c65b1445SDouglas Gilbert 		devip->stopped = !start;
1004c65b1445SDouglas Gilbert 	return 0;
1005c65b1445SDouglas Gilbert }
1006c65b1445SDouglas Gilbert 
100728898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
100828898873SFUJITA Tomonori {
100928898873SFUJITA Tomonori 	if (scsi_debug_virtual_gb > 0)
10105447ed6cSDouglas Gilbert 		return (sector_t)scsi_debug_virtual_gb *
10115447ed6cSDouglas Gilbert 			(1073741824 / scsi_debug_sector_size);
101228898873SFUJITA Tomonori 	else
101328898873SFUJITA Tomonori 		return sdebug_store_sectors;
101428898873SFUJITA Tomonori }
101528898873SFUJITA Tomonori 
10161da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
10171da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp,
10181da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
10191da177e4SLinus Torvalds {
10201da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1021c65b1445SDouglas Gilbert 	unsigned int capac;
10221da177e4SLinus Torvalds 	int errsts;
10231da177e4SLinus Torvalds 
1024c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
10251da177e4SLinus Torvalds 		return errsts;
1026c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
102728898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
10281da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1029c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1030c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
10311da177e4SLinus Torvalds 		arr[0] = (capac >> 24);
10321da177e4SLinus Torvalds 		arr[1] = (capac >> 16) & 0xff;
10331da177e4SLinus Torvalds 		arr[2] = (capac >> 8) & 0xff;
10341da177e4SLinus Torvalds 		arr[3] = capac & 0xff;
1035c65b1445SDouglas Gilbert 	} else {
1036c65b1445SDouglas Gilbert 		arr[0] = 0xff;
1037c65b1445SDouglas Gilbert 		arr[1] = 0xff;
1038c65b1445SDouglas Gilbert 		arr[2] = 0xff;
1039c65b1445SDouglas Gilbert 		arr[3] = 0xff;
1040c65b1445SDouglas Gilbert 	}
1041597136abSMartin K. Petersen 	arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
1042597136abSMartin K. Petersen 	arr[7] = scsi_debug_sector_size & 0xff;
10431da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
10441da177e4SLinus Torvalds }
10451da177e4SLinus Torvalds 
1046c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1047c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp,
1048c65b1445SDouglas Gilbert 			  struct sdebug_dev_info * devip)
1049c65b1445SDouglas Gilbert {
1050c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1051c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1052c65b1445SDouglas Gilbert 	unsigned long long capac;
1053c65b1445SDouglas Gilbert 	int errsts, k, alloc_len;
1054c65b1445SDouglas Gilbert 
1055c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1056c65b1445SDouglas Gilbert 		return errsts;
1057c65b1445SDouglas Gilbert 	alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1058c65b1445SDouglas Gilbert 		     + cmd[13]);
1059c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
106028898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1061c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1062c65b1445SDouglas Gilbert 	capac = sdebug_capacity - 1;
1063c65b1445SDouglas Gilbert 	for (k = 0; k < 8; ++k, capac >>= 8)
1064c65b1445SDouglas Gilbert 		arr[7 - k] = capac & 0xff;
1065597136abSMartin K. Petersen 	arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
1066597136abSMartin K. Petersen 	arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
1067597136abSMartin K. Petersen 	arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
1068597136abSMartin K. Petersen 	arr[11] = scsi_debug_sector_size & 0xff;
1069ea61fca5SMartin K. Petersen 	arr[13] = scsi_debug_physblk_exp & 0xf;
1070ea61fca5SMartin K. Petersen 	arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
107144d92694SMartin K. Petersen 
1072be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
10735b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1074be1dd78dSEric Sandeen 		if (scsi_debug_lbprz)
1075be1dd78dSEric Sandeen 			arr[14] |= 0x40; /* LBPRZ */
1076be1dd78dSEric Sandeen 	}
107744d92694SMartin K. Petersen 
1078ea61fca5SMartin K. Petersen 	arr[15] = scsi_debug_lowest_aligned & 0xff;
1079c6a44287SMartin K. Petersen 
1080c6a44287SMartin K. Petersen 	if (scsi_debug_dif) {
1081c6a44287SMartin K. Petersen 		arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
1082c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1083c6a44287SMartin K. Petersen 	}
1084c6a44287SMartin K. Petersen 
1085c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1086c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1087c65b1445SDouglas Gilbert }
1088c65b1445SDouglas Gilbert 
10895a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
10905a09e398SHannes Reinecke 
10915a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp,
10925a09e398SHannes Reinecke 			      struct sdebug_dev_info * devip)
10935a09e398SHannes Reinecke {
10945a09e398SHannes Reinecke 	unsigned char *cmd = (unsigned char *)scp->cmnd;
10955a09e398SHannes Reinecke 	unsigned char * arr;
10965a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
10975a09e398SHannes Reinecke 	int n, ret, alen, rlen;
10985a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
10995a09e398SHannes Reinecke 
11005a09e398SHannes Reinecke 	alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
11015a09e398SHannes Reinecke 		+ cmd[9]);
11025a09e398SHannes Reinecke 
11036f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
11046f3cbf55SDouglas Gilbert 	if (! arr)
11056f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
11065a09e398SHannes Reinecke 	/*
11075a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
11085a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
11095a09e398SHannes Reinecke 	 * So we create two port groups with one port each
11105a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
11115a09e398SHannes Reinecke 	 */
11125a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
11135a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
11145a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
11155a09e398SHannes Reinecke 	    (devip->channel & 0x7f);
11165a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
11175a09e398SHannes Reinecke 	    (devip->channel & 0x7f) + 0x80;
11185a09e398SHannes Reinecke 
11195a09e398SHannes Reinecke 	/*
11205a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
11215a09e398SHannes Reinecke 	 */
11225a09e398SHannes Reinecke 	n = 4;
11235a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno) {
11245a09e398SHannes Reinecke 	    arr[n++] = host_no % 3; /* Asymm access state */
11255a09e398SHannes Reinecke 	    arr[n++] = 0x0F; /* claim: all states are supported */
11265a09e398SHannes Reinecke 	} else {
11275a09e398SHannes Reinecke 	    arr[n++] = 0x0; /* Active/Optimized path */
11285a09e398SHannes Reinecke 	    arr[n++] = 0x01; /* claim: only support active/optimized paths */
11295a09e398SHannes Reinecke 	}
11305a09e398SHannes Reinecke 	arr[n++] = (port_group_a >> 8) & 0xff;
11315a09e398SHannes Reinecke 	arr[n++] = port_group_a & 0xff;
11325a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11335a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
11345a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
11355a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
11365a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11375a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11385a09e398SHannes Reinecke 	arr[n++] = (port_a >> 8) & 0xff;
11395a09e398SHannes Reinecke 	arr[n++] = port_a & 0xff;
11405a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
11415a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
11425a09e398SHannes Reinecke 	arr[n++] = (port_group_b >> 8) & 0xff;
11435a09e398SHannes Reinecke 	arr[n++] = port_group_b & 0xff;
11445a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11455a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
11465a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
11475a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
11485a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11495a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11505a09e398SHannes Reinecke 	arr[n++] = (port_b >> 8) & 0xff;
11515a09e398SHannes Reinecke 	arr[n++] = port_b & 0xff;
11525a09e398SHannes Reinecke 
11535a09e398SHannes Reinecke 	rlen = n - 4;
11545a09e398SHannes Reinecke 	arr[0] = (rlen >> 24) & 0xff;
11555a09e398SHannes Reinecke 	arr[1] = (rlen >> 16) & 0xff;
11565a09e398SHannes Reinecke 	arr[2] = (rlen >> 8) & 0xff;
11575a09e398SHannes Reinecke 	arr[3] = rlen & 0xff;
11585a09e398SHannes Reinecke 
11595a09e398SHannes Reinecke 	/*
11605a09e398SHannes Reinecke 	 * Return the smallest value of either
11615a09e398SHannes Reinecke 	 * - The allocated length
11625a09e398SHannes Reinecke 	 * - The constructed command length
11635a09e398SHannes Reinecke 	 * - The maximum array size
11645a09e398SHannes Reinecke 	 */
11655a09e398SHannes Reinecke 	rlen = min(alen,n);
11665a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
11675a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
11685a09e398SHannes Reinecke 	kfree(arr);
11695a09e398SHannes Reinecke 	return ret;
11705a09e398SHannes Reinecke }
11715a09e398SHannes Reinecke 
11721da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
11731da177e4SLinus Torvalds 
11741da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
11751da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
11761da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
11771da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
11781da177e4SLinus Torvalds 
11791da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
11801da177e4SLinus Torvalds 	if (1 == pcontrol)
11811da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
11821da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
11831da177e4SLinus Torvalds }
11841da177e4SLinus Torvalds 
11851da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
11861da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
11871da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
11881da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
11891da177e4SLinus Torvalds 
11901da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
11911da177e4SLinus Torvalds 	if (1 == pcontrol)
11921da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
11931da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
11941da177e4SLinus Torvalds }
11951da177e4SLinus Torvalds 
11961da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target)
11971da177e4SLinus Torvalds {       /* Format device page for mode_sense */
11981da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
11991da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
12001da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
12011da177e4SLinus Torvalds 
12021da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
12031da177e4SLinus Torvalds 	p[10] = (sdebug_sectors_per >> 8) & 0xff;
12041da177e4SLinus Torvalds 	p[11] = sdebug_sectors_per & 0xff;
1205597136abSMartin K. Petersen 	p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1206597136abSMartin K. Petersen 	p[13] = scsi_debug_sector_size & 0xff;
1207d986788bSMartin Pitt 	if (scsi_debug_removable)
12081da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
12091da177e4SLinus Torvalds 	if (1 == pcontrol)
12101da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
12111da177e4SLinus Torvalds 	return sizeof(format_pg);
12121da177e4SLinus Torvalds }
12131da177e4SLinus Torvalds 
12141da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
12151da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
12161da177e4SLinus Torvalds 	unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
12171da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
12181da177e4SLinus Torvalds 
12191da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
12201da177e4SLinus Torvalds 	if (1 == pcontrol)
12211da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(caching_pg) - 2);
12221da177e4SLinus Torvalds 	return sizeof(caching_pg);
12231da177e4SLinus Torvalds }
12241da177e4SLinus Torvalds 
12251da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
12261da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
1227c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1228c65b1445SDouglas Gilbert 				        0, 0, 0, 0};
1229c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
12301da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
12311da177e4SLinus Torvalds 
12321da177e4SLinus Torvalds 	if (scsi_debug_dsense)
12331da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
1234c65b1445SDouglas Gilbert 	else
1235c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
1236c6a44287SMartin K. Petersen 
1237c6a44287SMartin K. Petersen 	if (scsi_debug_ato)
1238c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1239c6a44287SMartin K. Petersen 
12401da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
12411da177e4SLinus Torvalds 	if (1 == pcontrol)
1242c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1243c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1244c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
12451da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
12461da177e4SLinus Torvalds }
12471da177e4SLinus Torvalds 
1248c65b1445SDouglas Gilbert 
12491da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
12501da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
1251c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
12521da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
1253c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1254c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
1255c65b1445SDouglas Gilbert 
12561da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
12571da177e4SLinus Torvalds 	if (1 == pcontrol)
1258c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1259c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1260c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
12611da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
12621da177e4SLinus Torvalds }
12631da177e4SLinus Torvalds 
1264c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1265c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
1266c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1267c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1268c65b1445SDouglas Gilbert 
1269c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1270c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1271c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1272c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
1273c65b1445SDouglas Gilbert }
1274c65b1445SDouglas Gilbert 
1275c65b1445SDouglas Gilbert 
1276c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1277c65b1445SDouglas Gilbert 			      int target_dev_id)
1278c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
1279c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1280c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1281c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1282c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1283c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
1284c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1285c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1286c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1287c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1288c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1289c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
1290c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1291c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1292c65b1445SDouglas Gilbert 		};
1293c65b1445SDouglas Gilbert 	int port_a, port_b;
1294c65b1445SDouglas Gilbert 
1295c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1296c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1297c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1298c65b1445SDouglas Gilbert 	p[20] = (port_a >> 24);
1299c65b1445SDouglas Gilbert 	p[21] = (port_a >> 16) & 0xff;
1300c65b1445SDouglas Gilbert 	p[22] = (port_a >> 8) & 0xff;
1301c65b1445SDouglas Gilbert 	p[23] = port_a & 0xff;
1302c65b1445SDouglas Gilbert 	p[48 + 20] = (port_b >> 24);
1303c65b1445SDouglas Gilbert 	p[48 + 21] = (port_b >> 16) & 0xff;
1304c65b1445SDouglas Gilbert 	p[48 + 22] = (port_b >> 8) & 0xff;
1305c65b1445SDouglas Gilbert 	p[48 + 23] = port_b & 0xff;
1306c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1307c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1308c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
1309c65b1445SDouglas Gilbert }
1310c65b1445SDouglas Gilbert 
1311c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1312c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
1313c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1314c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1315c65b1445SDouglas Gilbert 		};
1316c65b1445SDouglas Gilbert 
1317c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1318c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1319c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1320c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
1321c65b1445SDouglas Gilbert }
1322c65b1445SDouglas Gilbert 
13231da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
13241da177e4SLinus Torvalds 
13251da177e4SLinus Torvalds static int resp_mode_sense(struct scsi_cmnd * scp, int target,
13261da177e4SLinus Torvalds 			   struct sdebug_dev_info * devip)
13271da177e4SLinus Torvalds {
132823183910SDouglas Gilbert 	unsigned char dbd, llbaa;
132923183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
13301da177e4SLinus Torvalds 	unsigned char dev_spec;
133123183910SDouglas Gilbert 	int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
13321da177e4SLinus Torvalds 	unsigned char * ap;
13331da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
13341da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
13351da177e4SLinus Torvalds 
1336c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
13371da177e4SLinus Torvalds 		return errsts;
133823183910SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);
13391da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
13401da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
13411da177e4SLinus Torvalds 	subpcode = cmd[3];
13421da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
134323183910SDouglas Gilbert 	llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
134423183910SDouglas Gilbert 	if ((0 == scsi_debug_ptype) && (0 == dbd))
134523183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
134623183910SDouglas Gilbert 	else
134723183910SDouglas Gilbert 		bd_len = 0;
13481da177e4SLinus Torvalds 	alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
13491da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
13501da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
13511da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
13521da177e4SLinus Torvalds 			       	0);
13531da177e4SLinus Torvalds 		return check_condition_result;
13541da177e4SLinus Torvalds 	}
1355c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1356c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
135723183910SDouglas Gilbert 	/* set DPOFUA bit for disks */
135823183910SDouglas Gilbert 	if (0 == scsi_debug_ptype)
135923183910SDouglas Gilbert 		dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
136023183910SDouglas Gilbert 	else
136123183910SDouglas Gilbert 		dev_spec = 0x0;
13621da177e4SLinus Torvalds 	if (msense_6) {
13631da177e4SLinus Torvalds 		arr[2] = dev_spec;
136423183910SDouglas Gilbert 		arr[3] = bd_len;
13651da177e4SLinus Torvalds 		offset = 4;
13661da177e4SLinus Torvalds 	} else {
13671da177e4SLinus Torvalds 		arr[3] = dev_spec;
136823183910SDouglas Gilbert 		if (16 == bd_len)
136923183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
137023183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
13711da177e4SLinus Torvalds 		offset = 8;
13721da177e4SLinus Torvalds 	}
13731da177e4SLinus Torvalds 	ap = arr + offset;
137428898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
137528898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
137628898873SFUJITA Tomonori 
137723183910SDouglas Gilbert 	if (8 == bd_len) {
137823183910SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe) {
137923183910SDouglas Gilbert 			ap[0] = 0xff;
138023183910SDouglas Gilbert 			ap[1] = 0xff;
138123183910SDouglas Gilbert 			ap[2] = 0xff;
138223183910SDouglas Gilbert 			ap[3] = 0xff;
138323183910SDouglas Gilbert 		} else {
138423183910SDouglas Gilbert 			ap[0] = (sdebug_capacity >> 24) & 0xff;
138523183910SDouglas Gilbert 			ap[1] = (sdebug_capacity >> 16) & 0xff;
138623183910SDouglas Gilbert 			ap[2] = (sdebug_capacity >> 8) & 0xff;
138723183910SDouglas Gilbert 			ap[3] = sdebug_capacity & 0xff;
138823183910SDouglas Gilbert 		}
1389597136abSMartin K. Petersen 		ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1390597136abSMartin K. Petersen 		ap[7] = scsi_debug_sector_size & 0xff;
139123183910SDouglas Gilbert 		offset += bd_len;
139223183910SDouglas Gilbert 		ap = arr + offset;
139323183910SDouglas Gilbert 	} else if (16 == bd_len) {
139423183910SDouglas Gilbert 		unsigned long long capac = sdebug_capacity;
139523183910SDouglas Gilbert 
139623183910SDouglas Gilbert         	for (k = 0; k < 8; ++k, capac >>= 8)
139723183910SDouglas Gilbert                 	ap[7 - k] = capac & 0xff;
1398597136abSMartin K. Petersen 		ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1399597136abSMartin K. Petersen 		ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1400597136abSMartin K. Petersen 		ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1401597136abSMartin K. Petersen 		ap[15] = scsi_debug_sector_size & 0xff;
140223183910SDouglas Gilbert 		offset += bd_len;
140323183910SDouglas Gilbert 		ap = arr + offset;
140423183910SDouglas Gilbert 	}
14051da177e4SLinus Torvalds 
1406c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1407c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
14081da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
14091da177e4SLinus Torvalds 			       	0);
14101da177e4SLinus Torvalds 		return check_condition_result;
14111da177e4SLinus Torvalds 	}
14121da177e4SLinus Torvalds 	switch (pcode) {
14131da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
14141da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
14151da177e4SLinus Torvalds 		offset += len;
14161da177e4SLinus Torvalds 		break;
14171da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
14181da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
14191da177e4SLinus Torvalds 		offset += len;
14201da177e4SLinus Torvalds 		break;
14211da177e4SLinus Torvalds         case 0x3:       /* Format device page, direct access */
14221da177e4SLinus Torvalds                 len = resp_format_pg(ap, pcontrol, target);
14231da177e4SLinus Torvalds                 offset += len;
14241da177e4SLinus Torvalds                 break;
14251da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
14261da177e4SLinus Torvalds 		len = resp_caching_pg(ap, pcontrol, target);
14271da177e4SLinus Torvalds 		offset += len;
14281da177e4SLinus Torvalds 		break;
14291da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
14301da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
14311da177e4SLinus Torvalds 		offset += len;
14321da177e4SLinus Torvalds 		break;
1433c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
1434c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
1435c65b1445SDouglas Gilbert 		        mk_sense_buffer(devip, ILLEGAL_REQUEST,
1436c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1437c65b1445SDouglas Gilbert 			return check_condition_result;
1438c65b1445SDouglas Gilbert 	        }
1439c65b1445SDouglas Gilbert 		len = 0;
1440c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
1441c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1442c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
1443c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1444c65b1445SDouglas Gilbert 						  target_dev_id);
1445c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
1446c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
1447c65b1445SDouglas Gilbert 		offset += len;
1448c65b1445SDouglas Gilbert 		break;
14491da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
14501da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
14511da177e4SLinus Torvalds 		offset += len;
14521da177e4SLinus Torvalds 		break;
14531da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
1454c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
14551da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
14561da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
14571da177e4SLinus Torvalds 			len += resp_format_pg(ap + len, pcontrol, target);
14581da177e4SLinus Torvalds 			len += resp_caching_pg(ap + len, pcontrol, target);
14591da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1460c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1461c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
1462c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1463c65b1445SDouglas Gilbert 						  target, target_dev_id);
1464c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
1465c65b1445SDouglas Gilbert 			}
14661da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
1467c65b1445SDouglas Gilbert 		} else {
1468c65b1445SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
1469c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1470c65b1445SDouglas Gilbert 			return check_condition_result;
1471c65b1445SDouglas Gilbert                 }
14721da177e4SLinus Torvalds 		offset += len;
14731da177e4SLinus Torvalds 		break;
14741da177e4SLinus Torvalds 	default:
14751da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
14761da177e4SLinus Torvalds 			       	0);
14771da177e4SLinus Torvalds 		return check_condition_result;
14781da177e4SLinus Torvalds 	}
14791da177e4SLinus Torvalds 	if (msense_6)
14801da177e4SLinus Torvalds 		arr[0] = offset - 1;
14811da177e4SLinus Torvalds 	else {
14821da177e4SLinus Torvalds 		arr[0] = ((offset - 2) >> 8) & 0xff;
14831da177e4SLinus Torvalds 		arr[1] = (offset - 2) & 0xff;
14841da177e4SLinus Torvalds 	}
14851da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
14861da177e4SLinus Torvalds }
14871da177e4SLinus Torvalds 
1488c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
1489c65b1445SDouglas Gilbert 
1490c65b1445SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1491c65b1445SDouglas Gilbert 			    struct sdebug_dev_info * devip)
1492c65b1445SDouglas Gilbert {
1493c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1494c65b1445SDouglas Gilbert 	int param_len, res, errsts, mpage;
1495c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1496c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1497c65b1445SDouglas Gilbert 
1498c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1499c65b1445SDouglas Gilbert 		return errsts;
1500c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1501c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
1502c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
1503c65b1445SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1504c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1505c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1506c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
1507c65b1445SDouglas Gilbert 		return check_condition_result;
1508c65b1445SDouglas Gilbert 	}
1509c65b1445SDouglas Gilbert         res = fetch_to_dev_buffer(scp, arr, param_len);
1510c65b1445SDouglas Gilbert         if (-1 == res)
1511c65b1445SDouglas Gilbert                 return (DID_ERROR << 16);
1512c65b1445SDouglas Gilbert         else if ((res < param_len) &&
1513c65b1445SDouglas Gilbert                  (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1514c65b1445SDouglas Gilbert                 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1515c65b1445SDouglas Gilbert                        " IO sent=%d bytes\n", param_len, res);
1516c65b1445SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1517c65b1445SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
151823183910SDouglas Gilbert 	if (md_len > 2) {
1519c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1520c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_PARAM_LIST, 0);
1521c65b1445SDouglas Gilbert 		return check_condition_result;
1522c65b1445SDouglas Gilbert 	}
1523c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
1524c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
1525c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
1526c65b1445SDouglas Gilbert 	if (ps) {
1527c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1528c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_PARAM_LIST, 0);
1529c65b1445SDouglas Gilbert 		return check_condition_result;
1530c65b1445SDouglas Gilbert 	}
1531c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
1532c65b1445SDouglas Gilbert 	pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1533c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
1534c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
1535c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1536c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
1537c65b1445SDouglas Gilbert 		return check_condition_result;
1538c65b1445SDouglas Gilbert 	}
1539c65b1445SDouglas Gilbert 	switch (mpage) {
1540c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
1541c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
1542c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
1543c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
1544c65b1445SDouglas Gilbert 			scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1545c65b1445SDouglas Gilbert 			return 0;
1546c65b1445SDouglas Gilbert 		}
1547c65b1445SDouglas Gilbert 		break;
1548c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
1549c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
1550c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
1551c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
1552c65b1445SDouglas Gilbert 			return 0;
1553c65b1445SDouglas Gilbert 		}
1554c65b1445SDouglas Gilbert 		break;
1555c65b1445SDouglas Gilbert 	default:
1556c65b1445SDouglas Gilbert 		break;
1557c65b1445SDouglas Gilbert 	}
1558c65b1445SDouglas Gilbert 	mk_sense_buffer(devip, ILLEGAL_REQUEST,
1559c65b1445SDouglas Gilbert 			INVALID_FIELD_IN_PARAM_LIST, 0);
1560c65b1445SDouglas Gilbert 	return check_condition_result;
1561c65b1445SDouglas Gilbert }
1562c65b1445SDouglas Gilbert 
1563c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr)
1564c65b1445SDouglas Gilbert {
1565c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1566c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
1567c65b1445SDouglas Gilbert 		};
1568c65b1445SDouglas Gilbert 
1569c65b1445SDouglas Gilbert         memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1570c65b1445SDouglas Gilbert         return sizeof(temp_l_pg);
1571c65b1445SDouglas Gilbert }
1572c65b1445SDouglas Gilbert 
1573c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr)
1574c65b1445SDouglas Gilbert {
1575c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1576c65b1445SDouglas Gilbert 		};
1577c65b1445SDouglas Gilbert 
1578c65b1445SDouglas Gilbert         memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1579c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
1580c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
1581c65b1445SDouglas Gilbert 		arr[5] = 0xff;
1582c65b1445SDouglas Gilbert 	}
1583c65b1445SDouglas Gilbert         return sizeof(ie_l_pg);
1584c65b1445SDouglas Gilbert }
1585c65b1445SDouglas Gilbert 
1586c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
1587c65b1445SDouglas Gilbert 
1588c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp,
1589c65b1445SDouglas Gilbert                           struct sdebug_dev_info * devip)
1590c65b1445SDouglas Gilbert {
159123183910SDouglas Gilbert 	int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
1592c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1593c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1594c65b1445SDouglas Gilbert 
1595c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1596c65b1445SDouglas Gilbert 		return errsts;
1597c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1598c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
1599c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
1600c65b1445SDouglas Gilbert 	if (ppc || sp) {
1601c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1602c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
1603c65b1445SDouglas Gilbert 		return check_condition_result;
1604c65b1445SDouglas Gilbert 	}
1605c65b1445SDouglas Gilbert 	pcontrol = (cmd[2] & 0xc0) >> 6;
1606c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
160723183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
1608c65b1445SDouglas Gilbert 	alloc_len = (cmd[7] << 8) + cmd[8];
1609c65b1445SDouglas Gilbert 	arr[0] = pcode;
161023183910SDouglas Gilbert 	if (0 == subpcode) {
1611c65b1445SDouglas Gilbert 		switch (pcode) {
1612c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
1613c65b1445SDouglas Gilbert 			n = 4;
1614c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
1615c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
1616c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
1617c65b1445SDouglas Gilbert 			arr[3] = n - 4;
1618c65b1445SDouglas Gilbert 			break;
1619c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
1620c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
1621c65b1445SDouglas Gilbert 			break;
1622c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
1623c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
1624c65b1445SDouglas Gilbert 			break;
1625c65b1445SDouglas Gilbert 		default:
1626c65b1445SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
1627c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1628c65b1445SDouglas Gilbert 			return check_condition_result;
1629c65b1445SDouglas Gilbert 		}
163023183910SDouglas Gilbert 	} else if (0xff == subpcode) {
163123183910SDouglas Gilbert 		arr[0] |= 0x40;
163223183910SDouglas Gilbert 		arr[1] = subpcode;
163323183910SDouglas Gilbert 		switch (pcode) {
163423183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
163523183910SDouglas Gilbert 			n = 4;
163623183910SDouglas Gilbert 			arr[n++] = 0x0;
163723183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
163823183910SDouglas Gilbert 			arr[n++] = 0x0;
163923183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
164023183910SDouglas Gilbert 			arr[n++] = 0xd;
164123183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
164223183910SDouglas Gilbert 			arr[n++] = 0x2f;
164323183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
164423183910SDouglas Gilbert 			arr[3] = n - 4;
164523183910SDouglas Gilbert 			break;
164623183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
164723183910SDouglas Gilbert 			n = 4;
164823183910SDouglas Gilbert 			arr[n++] = 0xd;
164923183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
165023183910SDouglas Gilbert 			arr[3] = n - 4;
165123183910SDouglas Gilbert 			break;
165223183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
165323183910SDouglas Gilbert 			n = 4;
165423183910SDouglas Gilbert 			arr[n++] = 0x2f;
165523183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
165623183910SDouglas Gilbert 			arr[3] = n - 4;
165723183910SDouglas Gilbert 			break;
165823183910SDouglas Gilbert 		default:
165923183910SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
166023183910SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
166123183910SDouglas Gilbert 			return check_condition_result;
166223183910SDouglas Gilbert 		}
166323183910SDouglas Gilbert 	} else {
166423183910SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
166523183910SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
166623183910SDouglas Gilbert 		return check_condition_result;
166723183910SDouglas Gilbert 	}
1668c65b1445SDouglas Gilbert 	len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1669c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1670c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
1671c65b1445SDouglas Gilbert }
1672c65b1445SDouglas Gilbert 
167319789100SFUJITA Tomonori static int check_device_access_params(struct sdebug_dev_info *devi,
167419789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
16751da177e4SLinus Torvalds {
1676c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
167719789100SFUJITA Tomonori 		mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
16781da177e4SLinus Torvalds 		return check_condition_result;
16791da177e4SLinus Torvalds 	}
1680c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
1681c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
168219789100SFUJITA Tomonori 		mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
1683c65b1445SDouglas Gilbert 		return check_condition_result;
1684c65b1445SDouglas Gilbert 	}
168519789100SFUJITA Tomonori 	return 0;
168619789100SFUJITA Tomonori }
168719789100SFUJITA Tomonori 
1688a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
168919789100SFUJITA Tomonori static int do_device_access(struct scsi_cmnd *scmd,
169019789100SFUJITA Tomonori 			    struct sdebug_dev_info *devi,
169119789100SFUJITA Tomonori 			    unsigned long long lba, unsigned int num, int write)
169219789100SFUJITA Tomonori {
169319789100SFUJITA Tomonori 	int ret;
1694a361cc00SDarrick J. Wong 	unsigned long long block, rest = 0;
1695a4517511SAkinobu Mita 	struct scsi_data_buffer *sdb;
1696a4517511SAkinobu Mita 	enum dma_data_direction dir;
1697a4517511SAkinobu Mita 	size_t (*func)(struct scatterlist *, unsigned int, void *, size_t,
1698a4517511SAkinobu Mita 		       off_t);
169919789100SFUJITA Tomonori 
1700a4517511SAkinobu Mita 	if (write) {
1701a4517511SAkinobu Mita 		sdb = scsi_out(scmd);
1702a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
1703a4517511SAkinobu Mita 		func = sg_pcopy_to_buffer;
1704a4517511SAkinobu Mita 	} else {
1705a4517511SAkinobu Mita 		sdb = scsi_in(scmd);
1706a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
1707a4517511SAkinobu Mita 		func = sg_pcopy_from_buffer;
1708a4517511SAkinobu Mita 	}
1709a4517511SAkinobu Mita 
1710a4517511SAkinobu Mita 	if (!sdb->length)
1711a4517511SAkinobu Mita 		return 0;
1712a4517511SAkinobu Mita 	if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
1713a4517511SAkinobu Mita 		return -1;
171419789100SFUJITA Tomonori 
171519789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
171619789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
171719789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
171819789100SFUJITA Tomonori 
1719a4517511SAkinobu Mita 	ret = func(sdb->table.sgl, sdb->table.nents,
1720a4517511SAkinobu Mita 		   fake_storep + (block * scsi_debug_sector_size),
1721a4517511SAkinobu Mita 		   (num - rest) * scsi_debug_sector_size, 0);
1722a4517511SAkinobu Mita 	if (ret != (num - rest) * scsi_debug_sector_size)
1723a4517511SAkinobu Mita 		return ret;
1724a4517511SAkinobu Mita 
1725a4517511SAkinobu Mita 	if (rest) {
1726a4517511SAkinobu Mita 		ret += func(sdb->table.sgl, sdb->table.nents,
1727a4517511SAkinobu Mita 			    fake_storep, rest * scsi_debug_sector_size,
1728597136abSMartin K. Petersen 			    (num - rest) * scsi_debug_sector_size);
1729a4517511SAkinobu Mita 	}
173019789100SFUJITA Tomonori 
173119789100SFUJITA Tomonori 	return ret;
173219789100SFUJITA Tomonori }
173319789100SFUJITA Tomonori 
1734beb40ea4SAkinobu Mita static u16 dif_compute_csum(const void *buf, int len)
1735beb40ea4SAkinobu Mita {
1736beb40ea4SAkinobu Mita 	u16 csum;
1737beb40ea4SAkinobu Mita 
1738beb40ea4SAkinobu Mita 	switch (scsi_debug_guard) {
1739beb40ea4SAkinobu Mita 	case 1:
1740beb40ea4SAkinobu Mita 		csum = ip_compute_csum(buf, len);
1741beb40ea4SAkinobu Mita 		break;
1742beb40ea4SAkinobu Mita 	case 0:
1743beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
1744beb40ea4SAkinobu Mita 		break;
1745beb40ea4SAkinobu Mita 	}
1746beb40ea4SAkinobu Mita 	return csum;
1747beb40ea4SAkinobu Mita }
1748beb40ea4SAkinobu Mita 
1749beb40ea4SAkinobu Mita static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
1750beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
1751beb40ea4SAkinobu Mita {
1752beb40ea4SAkinobu Mita 	u16 csum = dif_compute_csum(data, scsi_debug_sector_size);
1753beb40ea4SAkinobu Mita 
1754beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
1755beb40ea4SAkinobu Mita 		pr_err("%s: GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
1756beb40ea4SAkinobu Mita 			__func__,
1757beb40ea4SAkinobu Mita 			(unsigned long)sector,
1758beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
1759beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
1760beb40ea4SAkinobu Mita 		return 0x01;
1761beb40ea4SAkinobu Mita 	}
1762beb40ea4SAkinobu Mita 	if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
1763beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
1764beb40ea4SAkinobu Mita 		pr_err("%s: REF check failed on sector %lu\n",
1765beb40ea4SAkinobu Mita 			__func__, (unsigned long)sector);
1766beb40ea4SAkinobu Mita 		return 0x03;
1767beb40ea4SAkinobu Mita 	}
1768beb40ea4SAkinobu Mita 	if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1769beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
1770beb40ea4SAkinobu Mita 		pr_err("%s: REF check failed on sector %lu\n",
1771beb40ea4SAkinobu Mita 			__func__, (unsigned long)sector);
1772beb40ea4SAkinobu Mita 			dif_errors++;
1773beb40ea4SAkinobu Mita 		return 0x03;
1774beb40ea4SAkinobu Mita 	}
1775beb40ea4SAkinobu Mita 	return 0;
1776beb40ea4SAkinobu Mita }
1777beb40ea4SAkinobu Mita 
1778c6a44287SMartin K. Petersen static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
1779395cef03SMartin K. Petersen 			    unsigned int sectors, u32 ei_lba)
1780c6a44287SMartin K. Petersen {
1781c6a44287SMartin K. Petersen 	unsigned int i, resid;
1782c6a44287SMartin K. Petersen 	struct scatterlist *psgl;
1783c6a44287SMartin K. Petersen 	struct sd_dif_tuple *sdt;
1784c6a44287SMartin K. Petersen 	sector_t sector;
1785c6a44287SMartin K. Petersen 	sector_t tmp_sec = start_sec;
1786c6a44287SMartin K. Petersen 	void *paddr;
1787c6a44287SMartin K. Petersen 
1788c6a44287SMartin K. Petersen 	start_sec = do_div(tmp_sec, sdebug_store_sectors);
1789c6a44287SMartin K. Petersen 
1790e18d8beaSAkinobu Mita 	sdt = dif_storep + start_sec;
1791c6a44287SMartin K. Petersen 
1792c6a44287SMartin K. Petersen 	for (i = 0 ; i < sectors ; i++) {
1793beb40ea4SAkinobu Mita 		int ret;
1794c6a44287SMartin K. Petersen 
1795c6a44287SMartin K. Petersen 		if (sdt[i].app_tag == 0xffff)
1796c6a44287SMartin K. Petersen 			continue;
1797c6a44287SMartin K. Petersen 
1798c6a44287SMartin K. Petersen 		sector = start_sec + i;
1799c6a44287SMartin K. Petersen 
1800beb40ea4SAkinobu Mita 		ret = dif_verify(&sdt[i],
1801beb40ea4SAkinobu Mita 				 fake_storep + sector * scsi_debug_sector_size,
1802beb40ea4SAkinobu Mita 				 sector, ei_lba);
1803beb40ea4SAkinobu Mita 		if (ret) {
1804c6a44287SMartin K. Petersen 			dif_errors++;
1805beb40ea4SAkinobu Mita 			return ret;
1806395cef03SMartin K. Petersen 		}
1807395cef03SMartin K. Petersen 
1808395cef03SMartin K. Petersen 		ei_lba++;
1809c6a44287SMartin K. Petersen 	}
1810c6a44287SMartin K. Petersen 
1811e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
1812e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
1813c6a44287SMartin K. Petersen 	sector = start_sec;
1814c6a44287SMartin K. Petersen 
1815c6a44287SMartin K. Petersen 	scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
1816c6a44287SMartin K. Petersen 		int len = min(psgl->length, resid);
1817c6a44287SMartin K. Petersen 
181877dfce07SCong Wang 		paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
1819e18d8beaSAkinobu Mita 		memcpy(paddr, dif_storep + sector, len);
1820c6a44287SMartin K. Petersen 
1821e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
1822c6a44287SMartin K. Petersen 		if (sector >= sdebug_store_sectors) {
1823c6a44287SMartin K. Petersen 			/* Force wrap */
1824c6a44287SMartin K. Petersen 			tmp_sec = sector;
1825c6a44287SMartin K. Petersen 			sector = do_div(tmp_sec, sdebug_store_sectors);
1826c6a44287SMartin K. Petersen 		}
1827c6a44287SMartin K. Petersen 		resid -= len;
182877dfce07SCong Wang 		kunmap_atomic(paddr);
1829c6a44287SMartin K. Petersen 	}
1830c6a44287SMartin K. Petersen 
1831c6a44287SMartin K. Petersen 	dix_reads++;
1832c6a44287SMartin K. Petersen 
1833c6a44287SMartin K. Petersen 	return 0;
1834c6a44287SMartin K. Petersen }
1835c6a44287SMartin K. Petersen 
183619789100SFUJITA Tomonori static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
1837395cef03SMartin K. Petersen 		     unsigned int num, struct sdebug_dev_info *devip,
1838395cef03SMartin K. Petersen 		     u32 ei_lba)
183919789100SFUJITA Tomonori {
184019789100SFUJITA Tomonori 	unsigned long iflags;
184119789100SFUJITA Tomonori 	int ret;
184219789100SFUJITA Tomonori 
184319789100SFUJITA Tomonori 	ret = check_device_access_params(devip, lba, num);
184419789100SFUJITA Tomonori 	if (ret)
184519789100SFUJITA Tomonori 		return ret;
184619789100SFUJITA Tomonori 
18471da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
184832f7ef73SDouglas Gilbert 	    (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
1849c65b1445SDouglas Gilbert 	    ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1850c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
185132f7ef73SDouglas Gilbert 		mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
1852c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
1853c65b1445SDouglas Gilbert 		if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1854c65b1445SDouglas Gilbert 			devip->sense_buff[0] |= 0x80;	/* Valid bit */
185532f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
185632f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
1857c65b1445SDouglas Gilbert 			devip->sense_buff[3] = (ret >> 24) & 0xff;
1858c65b1445SDouglas Gilbert 			devip->sense_buff[4] = (ret >> 16) & 0xff;
1859c65b1445SDouglas Gilbert 			devip->sense_buff[5] = (ret >> 8) & 0xff;
1860c65b1445SDouglas Gilbert 			devip->sense_buff[6] = ret & 0xff;
1861c65b1445SDouglas Gilbert 		}
1862a87e3a67SDouglas Gilbert 	        scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
18631da177e4SLinus Torvalds 		return check_condition_result;
18641da177e4SLinus Torvalds 	}
1865c6a44287SMartin K. Petersen 
1866c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
1867c6a44287SMartin K. Petersen 	if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
1868395cef03SMartin K. Petersen 		int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
1869c6a44287SMartin K. Petersen 
1870c6a44287SMartin K. Petersen 		if (prot_ret) {
1871c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
1872c6a44287SMartin K. Petersen 			return illegal_condition_result;
1873c6a44287SMartin K. Petersen 		}
1874c6a44287SMartin K. Petersen 	}
1875c6a44287SMartin K. Petersen 
18761da177e4SLinus Torvalds 	read_lock_irqsave(&atomic_rw, iflags);
187719789100SFUJITA Tomonori 	ret = do_device_access(SCpnt, devip, lba, num, 0);
18781da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
1879a4517511SAkinobu Mita 	if (ret == -1)
1880a4517511SAkinobu Mita 		return DID_ERROR << 16;
1881a4517511SAkinobu Mita 
1882a4517511SAkinobu Mita 	scsi_in(SCpnt)->resid = scsi_bufflen(SCpnt) - ret;
1883a4517511SAkinobu Mita 
1884a4517511SAkinobu Mita 	return 0;
18851da177e4SLinus Torvalds }
18861da177e4SLinus Torvalds 
1887c6a44287SMartin K. Petersen void dump_sector(unsigned char *buf, int len)
1888c6a44287SMartin K. Petersen {
1889c6a44287SMartin K. Petersen 	int i, j;
1890c6a44287SMartin K. Petersen 
1891c6a44287SMartin K. Petersen 	printk(KERN_ERR ">>> Sector Dump <<<\n");
1892c6a44287SMartin K. Petersen 
1893c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
1894c6a44287SMartin K. Petersen 		printk(KERN_ERR "%04d: ", i);
1895c6a44287SMartin K. Petersen 
1896c6a44287SMartin K. Petersen 		for (j = 0 ; j < 16 ; j++) {
1897c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
1898c6a44287SMartin K. Petersen 			if (c >= 0x20 && c < 0x7e)
1899c6a44287SMartin K. Petersen 				printk(" %c ", buf[i+j]);
1900c6a44287SMartin K. Petersen 			else
1901c6a44287SMartin K. Petersen 				printk("%02x ", buf[i+j]);
1902c6a44287SMartin K. Petersen 		}
1903c6a44287SMartin K. Petersen 
1904c6a44287SMartin K. Petersen 		printk("\n");
1905c6a44287SMartin K. Petersen 	}
1906c6a44287SMartin K. Petersen }
1907c6a44287SMartin K. Petersen 
1908c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
1909395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
1910c6a44287SMartin K. Petersen {
1911c6a44287SMartin K. Petersen 	int i, j, ret;
1912c6a44287SMartin K. Petersen 	struct sd_dif_tuple *sdt;
1913c6a44287SMartin K. Petersen 	struct scatterlist *dsgl = scsi_sglist(SCpnt);
1914c6a44287SMartin K. Petersen 	struct scatterlist *psgl = scsi_prot_sglist(SCpnt);
1915c6a44287SMartin K. Petersen 	void *daddr, *paddr;
1916c6a44287SMartin K. Petersen 	sector_t tmp_sec = start_sec;
1917c6a44287SMartin K. Petersen 	sector_t sector;
1918c6a44287SMartin K. Petersen 	int ppage_offset;
1919c6a44287SMartin K. Petersen 
1920c6a44287SMartin K. Petersen 	sector = do_div(tmp_sec, sdebug_store_sectors);
1921c6a44287SMartin K. Petersen 
1922c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
1923c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
1924c6a44287SMartin K. Petersen 
1925c6a44287SMartin K. Petersen 	ppage_offset = 0;
1926c6a44287SMartin K. Petersen 
1927c6a44287SMartin K. Petersen 	/* For each data page */
1928c6a44287SMartin K. Petersen 	scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
192977dfce07SCong Wang 		daddr = kmap_atomic(sg_page(dsgl)) + dsgl->offset;
1930fc3fc352SAkinobu Mita 		paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
1931c6a44287SMartin K. Petersen 
1932c6a44287SMartin K. Petersen 		/* For each sector-sized chunk in data page */
1933c6a44287SMartin K. Petersen 		for (j = 0; j < dsgl->length; j += scsi_debug_sector_size) {
1934c6a44287SMartin K. Petersen 
1935c6a44287SMartin K. Petersen 			/* If we're at the end of the current
1936c6a44287SMartin K. Petersen 			 * protection page advance to the next one
1937c6a44287SMartin K. Petersen 			 */
1938c6a44287SMartin K. Petersen 			if (ppage_offset >= psgl->length) {
193977dfce07SCong Wang 				kunmap_atomic(paddr);
1940c6a44287SMartin K. Petersen 				psgl = sg_next(psgl);
1941c6a44287SMartin K. Petersen 				BUG_ON(psgl == NULL);
194277dfce07SCong Wang 				paddr = kmap_atomic(sg_page(psgl))
1943c6a44287SMartin K. Petersen 					+ psgl->offset;
1944c6a44287SMartin K. Petersen 				ppage_offset = 0;
1945c6a44287SMartin K. Petersen 			}
1946c6a44287SMartin K. Petersen 
1947c6a44287SMartin K. Petersen 			sdt = paddr + ppage_offset;
1948c6a44287SMartin K. Petersen 
1949beb40ea4SAkinobu Mita 			ret = dif_verify(sdt, daddr + j, start_sec, ei_lba);
1950beb40ea4SAkinobu Mita 			if (ret) {
1951518d9df8SAkinobu Mita 				dump_sector(daddr + j, scsi_debug_sector_size);
1952395cef03SMartin K. Petersen 				goto out;
1953395cef03SMartin K. Petersen 			}
1954395cef03SMartin K. Petersen 
1955c6a44287SMartin K. Petersen 			/* Would be great to copy this in bigger
1956c6a44287SMartin K. Petersen 			 * chunks.  However, for the sake of
1957c6a44287SMartin K. Petersen 			 * correctness we need to verify each sector
1958c6a44287SMartin K. Petersen 			 * before writing it to "stable" storage
1959c6a44287SMartin K. Petersen 			 */
1960e18d8beaSAkinobu Mita 			memcpy(dif_storep + sector, sdt, sizeof(*sdt));
1961c6a44287SMartin K. Petersen 
1962c6a44287SMartin K. Petersen 			sector++;
1963c6a44287SMartin K. Petersen 
1964c6a44287SMartin K. Petersen 			if (sector == sdebug_store_sectors)
1965c6a44287SMartin K. Petersen 				sector = 0;	/* Force wrap */
1966c6a44287SMartin K. Petersen 
1967c6a44287SMartin K. Petersen 			start_sec++;
1968395cef03SMartin K. Petersen 			ei_lba++;
1969c6a44287SMartin K. Petersen 			ppage_offset += sizeof(struct sd_dif_tuple);
1970c6a44287SMartin K. Petersen 		}
1971c6a44287SMartin K. Petersen 
1972fc3fc352SAkinobu Mita 		kunmap_atomic(paddr);
197377dfce07SCong Wang 		kunmap_atomic(daddr);
1974c6a44287SMartin K. Petersen 	}
1975c6a44287SMartin K. Petersen 
1976c6a44287SMartin K. Petersen 	dix_writes++;
1977c6a44287SMartin K. Petersen 
1978c6a44287SMartin K. Petersen 	return 0;
1979c6a44287SMartin K. Petersen 
1980c6a44287SMartin K. Petersen out:
1981c6a44287SMartin K. Petersen 	dif_errors++;
198277dfce07SCong Wang 	kunmap_atomic(paddr);
1983fc3fc352SAkinobu Mita 	kunmap_atomic(daddr);
1984c6a44287SMartin K. Petersen 	return ret;
1985c6a44287SMartin K. Petersen }
1986c6a44287SMartin K. Petersen 
1987b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
1988b90ebc3dSAkinobu Mita {
1989b90ebc3dSAkinobu Mita 	if (scsi_debug_unmap_alignment) {
1990b90ebc3dSAkinobu Mita 		lba += scsi_debug_unmap_granularity -
1991b90ebc3dSAkinobu Mita 			scsi_debug_unmap_alignment;
1992b90ebc3dSAkinobu Mita 	}
1993b90ebc3dSAkinobu Mita 	do_div(lba, scsi_debug_unmap_granularity);
1994b90ebc3dSAkinobu Mita 
1995b90ebc3dSAkinobu Mita 	return lba;
1996b90ebc3dSAkinobu Mita }
1997b90ebc3dSAkinobu Mita 
1998b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
1999b90ebc3dSAkinobu Mita {
2000a027b5b9SAkinobu Mita 	sector_t lba = index * scsi_debug_unmap_granularity;
2001a027b5b9SAkinobu Mita 
2002a027b5b9SAkinobu Mita 	if (scsi_debug_unmap_alignment) {
2003a027b5b9SAkinobu Mita 		lba -= scsi_debug_unmap_granularity -
2004b90ebc3dSAkinobu Mita 			scsi_debug_unmap_alignment;
2005b90ebc3dSAkinobu Mita 	}
2006b90ebc3dSAkinobu Mita 
2007a027b5b9SAkinobu Mita 	return lba;
2008a027b5b9SAkinobu Mita }
2009a027b5b9SAkinobu Mita 
201044d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
201144d92694SMartin K. Petersen {
2012b90ebc3dSAkinobu Mita 	sector_t end;
2013b90ebc3dSAkinobu Mita 	unsigned int mapped;
2014b90ebc3dSAkinobu Mita 	unsigned long index;
2015b90ebc3dSAkinobu Mita 	unsigned long next;
201644d92694SMartin K. Petersen 
2017b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
2018b90ebc3dSAkinobu Mita 	mapped = test_bit(index, map_storep);
201944d92694SMartin K. Petersen 
202044d92694SMartin K. Petersen 	if (mapped)
2021b90ebc3dSAkinobu Mita 		next = find_next_zero_bit(map_storep, map_size, index);
202244d92694SMartin K. Petersen 	else
2023b90ebc3dSAkinobu Mita 		next = find_next_bit(map_storep, map_size, index);
202444d92694SMartin K. Petersen 
2025b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
202644d92694SMartin K. Petersen 	*num = end - lba;
202744d92694SMartin K. Petersen 
202844d92694SMartin K. Petersen 	return mapped;
202944d92694SMartin K. Petersen }
203044d92694SMartin K. Petersen 
203144d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
203244d92694SMartin K. Petersen {
203344d92694SMartin K. Petersen 	sector_t end = lba + len;
203444d92694SMartin K. Petersen 
203544d92694SMartin K. Petersen 	while (lba < end) {
2036b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
203744d92694SMartin K. Petersen 
2038b90ebc3dSAkinobu Mita 		if (index < map_size)
2039b90ebc3dSAkinobu Mita 			set_bit(index, map_storep);
204044d92694SMartin K. Petersen 
2041b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
204244d92694SMartin K. Petersen 	}
204344d92694SMartin K. Petersen }
204444d92694SMartin K. Petersen 
204544d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
204644d92694SMartin K. Petersen {
204744d92694SMartin K. Petersen 	sector_t end = lba + len;
204844d92694SMartin K. Petersen 
204944d92694SMartin K. Petersen 	while (lba < end) {
2050b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
205144d92694SMartin K. Petersen 
2052b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
2053b90ebc3dSAkinobu Mita 		    lba + scsi_debug_unmap_granularity <= end &&
2054b90ebc3dSAkinobu Mita 		    index < map_size) {
2055b90ebc3dSAkinobu Mita 			clear_bit(index, map_storep);
2056b90ebc3dSAkinobu Mita 			if (scsi_debug_lbprz) {
2057be1dd78dSEric Sandeen 				memset(fake_storep +
2058cc34a8e6SAkinobu Mita 				       lba * scsi_debug_sector_size, 0,
2059cc34a8e6SAkinobu Mita 				       scsi_debug_sector_size *
2060cc34a8e6SAkinobu Mita 				       scsi_debug_unmap_granularity);
2061be1dd78dSEric Sandeen 			}
2062e9926b43SAkinobu Mita 			if (dif_storep) {
2063e9926b43SAkinobu Mita 				memset(dif_storep + lba, 0xff,
2064e9926b43SAkinobu Mita 				       sizeof(*dif_storep) *
2065e9926b43SAkinobu Mita 				       scsi_debug_unmap_granularity);
2066e9926b43SAkinobu Mita 			}
2067b90ebc3dSAkinobu Mita 		}
2068b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
206944d92694SMartin K. Petersen 	}
207044d92694SMartin K. Petersen }
207144d92694SMartin K. Petersen 
2072c65b1445SDouglas Gilbert static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
2073395cef03SMartin K. Petersen 		      unsigned int num, struct sdebug_dev_info *devip,
2074395cef03SMartin K. Petersen 		      u32 ei_lba)
20751da177e4SLinus Torvalds {
20761da177e4SLinus Torvalds 	unsigned long iflags;
207719789100SFUJITA Tomonori 	int ret;
20781da177e4SLinus Torvalds 
207919789100SFUJITA Tomonori 	ret = check_device_access_params(devip, lba, num);
208019789100SFUJITA Tomonori 	if (ret)
208119789100SFUJITA Tomonori 		return ret;
20821da177e4SLinus Torvalds 
2083c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2084c6a44287SMartin K. Petersen 	if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
2085395cef03SMartin K. Petersen 		int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
2086c6a44287SMartin K. Petersen 
2087c6a44287SMartin K. Petersen 		if (prot_ret) {
2088c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
2089c6a44287SMartin K. Petersen 			return illegal_condition_result;
2090c6a44287SMartin K. Petersen 		}
2091c6a44287SMartin K. Petersen 	}
2092c6a44287SMartin K. Petersen 
20931da177e4SLinus Torvalds 	write_lock_irqsave(&atomic_rw, iflags);
209419789100SFUJITA Tomonori 	ret = do_device_access(SCpnt, devip, lba, num, 1);
20959ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
209644d92694SMartin K. Petersen 		map_region(lba, num);
20971da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
209819789100SFUJITA Tomonori 	if (-1 == ret)
20991da177e4SLinus Torvalds 		return (DID_ERROR << 16);
2100597136abSMartin K. Petersen 	else if ((ret < (num * scsi_debug_sector_size)) &&
21011da177e4SLinus Torvalds 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
2102c65b1445SDouglas Gilbert 		printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
2103597136abSMartin K. Petersen 		       " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
210444d92694SMartin K. Petersen 
21051da177e4SLinus Torvalds 	return 0;
21061da177e4SLinus Torvalds }
21071da177e4SLinus Torvalds 
210844d92694SMartin K. Petersen static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,
210944d92694SMartin K. Petersen 		      unsigned int num, struct sdebug_dev_info *devip,
211044d92694SMartin K. Petersen 			   u32 ei_lba, unsigned int unmap)
211144d92694SMartin K. Petersen {
211244d92694SMartin K. Petersen 	unsigned long iflags;
211344d92694SMartin K. Petersen 	unsigned long long i;
211444d92694SMartin K. Petersen 	int ret;
211544d92694SMartin K. Petersen 
211644d92694SMartin K. Petersen 	ret = check_device_access_params(devip, lba, num);
211744d92694SMartin K. Petersen 	if (ret)
211844d92694SMartin K. Petersen 		return ret;
211944d92694SMartin K. Petersen 
21205b94e232SMartin K. Petersen 	if (num > scsi_debug_write_same_length) {
21215b94e232SMartin K. Petersen 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
21225b94e232SMartin K. Petersen 				0);
21235b94e232SMartin K. Petersen 		return check_condition_result;
21245b94e232SMartin K. Petersen 	}
21255b94e232SMartin K. Petersen 
212644d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
212744d92694SMartin K. Petersen 
21289ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
212944d92694SMartin K. Petersen 		unmap_region(lba, num);
213044d92694SMartin K. Petersen 		goto out;
213144d92694SMartin K. Petersen 	}
213244d92694SMartin K. Petersen 
213344d92694SMartin K. Petersen 	/* Else fetch one logical block */
213444d92694SMartin K. Petersen 	ret = fetch_to_dev_buffer(scmd,
213544d92694SMartin K. Petersen 				  fake_storep + (lba * scsi_debug_sector_size),
213644d92694SMartin K. Petersen 				  scsi_debug_sector_size);
213744d92694SMartin K. Petersen 
213844d92694SMartin K. Petersen 	if (-1 == ret) {
213944d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
214044d92694SMartin K. Petersen 		return (DID_ERROR << 16);
214144d92694SMartin K. Petersen 	} else if ((ret < (num * scsi_debug_sector_size)) &&
214244d92694SMartin K. Petersen 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
214344d92694SMartin K. Petersen 		printk(KERN_INFO "scsi_debug: write same: cdb indicated=%u, "
214444d92694SMartin K. Petersen 		       " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
214544d92694SMartin K. Petersen 
214644d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
214744d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
214844d92694SMartin K. Petersen 		memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size),
214944d92694SMartin K. Petersen 		       fake_storep + (lba * scsi_debug_sector_size),
215044d92694SMartin K. Petersen 		       scsi_debug_sector_size);
215144d92694SMartin K. Petersen 
21529ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
215344d92694SMartin K. Petersen 		map_region(lba, num);
215444d92694SMartin K. Petersen out:
215544d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
215644d92694SMartin K. Petersen 
215744d92694SMartin K. Petersen 	return 0;
215844d92694SMartin K. Petersen }
215944d92694SMartin K. Petersen 
216044d92694SMartin K. Petersen struct unmap_block_desc {
216144d92694SMartin K. Petersen 	__be64	lba;
216244d92694SMartin K. Petersen 	__be32	blocks;
216344d92694SMartin K. Petersen 	__be32	__reserved;
216444d92694SMartin K. Petersen };
216544d92694SMartin K. Petersen 
216644d92694SMartin K. Petersen static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
216744d92694SMartin K. Petersen {
216844d92694SMartin K. Petersen 	unsigned char *buf;
216944d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
217044d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
217144d92694SMartin K. Petersen 	int ret;
217244d92694SMartin K. Petersen 
217344d92694SMartin K. Petersen 	ret = check_readiness(scmd, 1, devip);
217444d92694SMartin K. Petersen 	if (ret)
217544d92694SMartin K. Petersen 		return ret;
217644d92694SMartin K. Petersen 
217744d92694SMartin K. Petersen 	payload_len = get_unaligned_be16(&scmd->cmnd[7]);
217844d92694SMartin K. Petersen 	BUG_ON(scsi_bufflen(scmd) != payload_len);
217944d92694SMartin K. Petersen 
218044d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
218144d92694SMartin K. Petersen 
218244d92694SMartin K. Petersen 	buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC);
218344d92694SMartin K. Petersen 	if (!buf)
218444d92694SMartin K. Petersen 		return check_condition_result;
218544d92694SMartin K. Petersen 
218644d92694SMartin K. Petersen 	scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
218744d92694SMartin K. Petersen 
218844d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
218944d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
219044d92694SMartin K. Petersen 
219144d92694SMartin K. Petersen 	desc = (void *)&buf[8];
219244d92694SMartin K. Petersen 
219344d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
219444d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
219544d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
219644d92694SMartin K. Petersen 
219744d92694SMartin K. Petersen 		ret = check_device_access_params(devip, lba, num);
219844d92694SMartin K. Petersen 		if (ret)
219944d92694SMartin K. Petersen 			goto out;
220044d92694SMartin K. Petersen 
220144d92694SMartin K. Petersen 		unmap_region(lba, num);
220244d92694SMartin K. Petersen 	}
220344d92694SMartin K. Petersen 
220444d92694SMartin K. Petersen 	ret = 0;
220544d92694SMartin K. Petersen 
220644d92694SMartin K. Petersen out:
220744d92694SMartin K. Petersen 	kfree(buf);
220844d92694SMartin K. Petersen 
220944d92694SMartin K. Petersen 	return ret;
221044d92694SMartin K. Petersen }
221144d92694SMartin K. Petersen 
221244d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
221344d92694SMartin K. Petersen 
221444d92694SMartin K. Petersen static int resp_get_lba_status(struct scsi_cmnd * scmd,
221544d92694SMartin K. Petersen 			       struct sdebug_dev_info * devip)
221644d92694SMartin K. Petersen {
221744d92694SMartin K. Petersen 	unsigned long long lba;
221844d92694SMartin K. Petersen 	unsigned int alloc_len, mapped, num;
221944d92694SMartin K. Petersen 	unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN];
222044d92694SMartin K. Petersen 	int ret;
222144d92694SMartin K. Petersen 
222244d92694SMartin K. Petersen 	ret = check_readiness(scmd, 1, devip);
222344d92694SMartin K. Petersen 	if (ret)
222444d92694SMartin K. Petersen 		return ret;
222544d92694SMartin K. Petersen 
222644d92694SMartin K. Petersen 	lba = get_unaligned_be64(&scmd->cmnd[2]);
222744d92694SMartin K. Petersen 	alloc_len = get_unaligned_be32(&scmd->cmnd[10]);
222844d92694SMartin K. Petersen 
222944d92694SMartin K. Petersen 	if (alloc_len < 24)
223044d92694SMartin K. Petersen 		return 0;
223144d92694SMartin K. Petersen 
223244d92694SMartin K. Petersen 	ret = check_device_access_params(devip, lba, 1);
223344d92694SMartin K. Petersen 	if (ret)
223444d92694SMartin K. Petersen 		return ret;
223544d92694SMartin K. Petersen 
223644d92694SMartin K. Petersen 	mapped = map_state(lba, &num);
223744d92694SMartin K. Petersen 
223844d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
2239de13e965SDouglas Gilbert 	put_unaligned_be32(20, &arr[0]);	/* Parameter Data Length */
224044d92694SMartin K. Petersen 	put_unaligned_be64(lba, &arr[8]);	/* LBA */
224144d92694SMartin K. Petersen 	put_unaligned_be32(num, &arr[16]);	/* Number of blocks */
224244d92694SMartin K. Petersen 	arr[20] = !mapped;			/* mapped = 0, unmapped = 1 */
224344d92694SMartin K. Petersen 
224444d92694SMartin K. Petersen 	return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN);
224544d92694SMartin K. Petersen }
224644d92694SMartin K. Petersen 
2247c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256
22481da177e4SLinus Torvalds 
22491da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp,
22501da177e4SLinus Torvalds 			    struct sdebug_dev_info * devip)
22511da177e4SLinus Torvalds {
22521da177e4SLinus Torvalds 	unsigned int alloc_len;
2253c65b1445SDouglas Gilbert 	int lun_cnt, i, upper, num, n, wlun, lun;
22541da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
22551da177e4SLinus Torvalds 	int select_report = (int)cmd[2];
22561da177e4SLinus Torvalds 	struct scsi_lun *one_lun;
22571da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_RLUN_ARR_SZ];
2258c65b1445SDouglas Gilbert 	unsigned char * max_addr;
22591da177e4SLinus Torvalds 
22601da177e4SLinus Torvalds 	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
2261c65b1445SDouglas Gilbert 	if ((alloc_len < 4) || (select_report > 2)) {
22621da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
22631da177e4SLinus Torvalds 			       	0);
22641da177e4SLinus Torvalds 		return check_condition_result;
22651da177e4SLinus Torvalds 	}
22661da177e4SLinus Torvalds 	/* can produce response with up to 16k luns (lun 0 to lun 16383) */
22671da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
22681da177e4SLinus Torvalds 	lun_cnt = scsi_debug_max_luns;
2269c65b1445SDouglas Gilbert 	if (1 == select_report)
2270c65b1445SDouglas Gilbert 		lun_cnt = 0;
2271c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
2272c65b1445SDouglas Gilbert 		--lun_cnt;
2273c65b1445SDouglas Gilbert 	wlun = (select_report > 0) ? 1 : 0;
2274c65b1445SDouglas Gilbert 	num = lun_cnt + wlun;
2275c65b1445SDouglas Gilbert 	arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
2276c65b1445SDouglas Gilbert 	arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
2277c65b1445SDouglas Gilbert 	n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
2278c65b1445SDouglas Gilbert 			    sizeof(struct scsi_lun)), num);
2279c65b1445SDouglas Gilbert 	if (n < num) {
2280c65b1445SDouglas Gilbert 		wlun = 0;
2281c65b1445SDouglas Gilbert 		lun_cnt = n;
2282c65b1445SDouglas Gilbert 	}
22831da177e4SLinus Torvalds 	one_lun = (struct scsi_lun *) &arr[8];
2284c65b1445SDouglas Gilbert 	max_addr = arr + SDEBUG_RLUN_ARR_SZ;
2285c65b1445SDouglas Gilbert 	for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
2286c65b1445SDouglas Gilbert              ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
2287c65b1445SDouglas Gilbert 	     i++, lun++) {
2288c65b1445SDouglas Gilbert 		upper = (lun >> 8) & 0x3f;
22891da177e4SLinus Torvalds 		if (upper)
22901da177e4SLinus Torvalds 			one_lun[i].scsi_lun[0] =
22911da177e4SLinus Torvalds 			    (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
2292c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = lun & 0xff;
22931da177e4SLinus Torvalds 	}
2294c65b1445SDouglas Gilbert 	if (wlun) {
2295c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
2296c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
2297c65b1445SDouglas Gilbert 		i++;
2298c65b1445SDouglas Gilbert 	}
2299c65b1445SDouglas Gilbert 	alloc_len = (unsigned char *)(one_lun + i) - arr;
23001da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr,
23011da177e4SLinus Torvalds 				    min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
23021da177e4SLinus Torvalds }
23031da177e4SLinus Torvalds 
2304c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
2305c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
2306c639d14eSFUJITA Tomonori {
2307c639d14eSFUJITA Tomonori 	int i, j, ret = -1;
2308c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
2309c639d14eSFUJITA Tomonori 	unsigned int offset;
2310c639d14eSFUJITA Tomonori 	struct scatterlist *sg;
2311c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
2312c639d14eSFUJITA Tomonori 
2313c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
2314c639d14eSFUJITA Tomonori 	buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
2315c639d14eSFUJITA Tomonori 	if (!buf)
2316c639d14eSFUJITA Tomonori 		return ret;
2317c639d14eSFUJITA Tomonori 
231821a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
2319c639d14eSFUJITA Tomonori 
2320c639d14eSFUJITA Tomonori 	offset = 0;
2321c639d14eSFUJITA Tomonori 	for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
232277dfce07SCong Wang 		kaddr = (unsigned char *)kmap_atomic(sg_page(sg));
2323c639d14eSFUJITA Tomonori 		if (!kaddr)
2324c639d14eSFUJITA Tomonori 			goto out;
2325c639d14eSFUJITA Tomonori 
2326c639d14eSFUJITA Tomonori 		for (j = 0; j < sg->length; j++)
2327c639d14eSFUJITA Tomonori 			*(kaddr + sg->offset + j) ^= *(buf + offset + j);
2328c639d14eSFUJITA Tomonori 
2329c639d14eSFUJITA Tomonori 		offset += sg->length;
233077dfce07SCong Wang 		kunmap_atomic(kaddr);
2331c639d14eSFUJITA Tomonori 	}
2332c639d14eSFUJITA Tomonori 	ret = 0;
2333c639d14eSFUJITA Tomonori out:
2334c639d14eSFUJITA Tomonori 	kfree(buf);
2335c639d14eSFUJITA Tomonori 
2336c639d14eSFUJITA Tomonori 	return ret;
2337c639d14eSFUJITA Tomonori }
2338c639d14eSFUJITA Tomonori 
23391da177e4SLinus Torvalds /* When timer goes off this function is called. */
23401da177e4SLinus Torvalds static void timer_intr_handler(unsigned long indx)
23411da177e4SLinus Torvalds {
23421da177e4SLinus Torvalds 	struct sdebug_queued_cmd * sqcp;
23431da177e4SLinus Torvalds 	unsigned long iflags;
23441da177e4SLinus Torvalds 
234578d4e5a0SDouglas Gilbert 	if (indx >= scsi_debug_max_queue) {
23461da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
23471da177e4SLinus Torvalds 		       "large\n");
23481da177e4SLinus Torvalds 		return;
23491da177e4SLinus Torvalds 	}
23501da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
23511da177e4SLinus Torvalds 	sqcp = &queued_arr[(int)indx];
23521da177e4SLinus Torvalds 	if (! sqcp->in_use) {
23531da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
23541da177e4SLinus Torvalds 		       "interrupt\n");
23551da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
23561da177e4SLinus Torvalds 		return;
23571da177e4SLinus Torvalds 	}
23581da177e4SLinus Torvalds 	sqcp->in_use = 0;
23591da177e4SLinus Torvalds 	if (sqcp->done_funct) {
23601da177e4SLinus Torvalds 		sqcp->a_cmnd->result = sqcp->scsi_result;
23611da177e4SLinus Torvalds 		sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
23621da177e4SLinus Torvalds 	}
23631da177e4SLinus Torvalds 	sqcp->done_funct = NULL;
23641da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
23651da177e4SLinus Torvalds }
23661da177e4SLinus Torvalds 
23671da177e4SLinus Torvalds 
23688dea0d02SFUJITA Tomonori static struct sdebug_dev_info *
23698dea0d02SFUJITA Tomonori sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
23705cb2fc06SFUJITA Tomonori {
23715cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
23725cb2fc06SFUJITA Tomonori 
23735cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
23745cb2fc06SFUJITA Tomonori 	if (devip) {
23755cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
23765cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
23775cb2fc06SFUJITA Tomonori 	}
23785cb2fc06SFUJITA Tomonori 	return devip;
23795cb2fc06SFUJITA Tomonori }
23805cb2fc06SFUJITA Tomonori 
23811da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
23821da177e4SLinus Torvalds {
23831da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
23841da177e4SLinus Torvalds 	struct sdebug_dev_info * open_devip = NULL;
23851da177e4SLinus Torvalds 	struct sdebug_dev_info * devip =
23861da177e4SLinus Torvalds 			(struct sdebug_dev_info *)sdev->hostdata;
23871da177e4SLinus Torvalds 
23881da177e4SLinus Torvalds 	if (devip)
23891da177e4SLinus Torvalds 		return devip;
2390d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
23911da177e4SLinus Torvalds 	if (!sdbg_host) {
23921da177e4SLinus Torvalds                 printk(KERN_ERR "Host info NULL\n");
23931da177e4SLinus Torvalds 		return NULL;
23941da177e4SLinus Torvalds         }
23951da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
23961da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
23971da177e4SLinus Torvalds                     (devip->target == sdev->id) &&
23981da177e4SLinus Torvalds                     (devip->lun == sdev->lun))
23991da177e4SLinus Torvalds                         return devip;
24001da177e4SLinus Torvalds 		else {
24011da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
24021da177e4SLinus Torvalds 				open_devip = devip;
24031da177e4SLinus Torvalds 		}
24041da177e4SLinus Torvalds 	}
24055cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
24065cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
24075cb2fc06SFUJITA Tomonori 		if (!open_devip) {
24081da177e4SLinus Torvalds 			printk(KERN_ERR "%s: out of memory at line %d\n",
2409cadbd4a5SHarvey Harrison 				__func__, __LINE__);
24101da177e4SLinus Torvalds 			return NULL;
24111da177e4SLinus Torvalds 		}
24121da177e4SLinus Torvalds 	}
2413a75869d1SFUJITA Tomonori 
24141da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
24151da177e4SLinus Torvalds 	open_devip->target = sdev->id;
24161da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
24171da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
24181da177e4SLinus Torvalds 	open_devip->reset = 1;
24191da177e4SLinus Torvalds 	open_devip->used = 1;
24201da177e4SLinus Torvalds 	memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
24211da177e4SLinus Torvalds 	if (scsi_debug_dsense)
24221da177e4SLinus Torvalds 		open_devip->sense_buff[0] = 0x72;
24231da177e4SLinus Torvalds 	else {
24241da177e4SLinus Torvalds 		open_devip->sense_buff[0] = 0x70;
24251da177e4SLinus Torvalds 		open_devip->sense_buff[7] = 0xa;
24261da177e4SLinus Torvalds 	}
2427c65b1445SDouglas Gilbert 	if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2428c65b1445SDouglas Gilbert 		open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
2429a75869d1SFUJITA Tomonori 
24301da177e4SLinus Torvalds 	return open_devip;
24311da177e4SLinus Torvalds }
24321da177e4SLinus Torvalds 
24338dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
24341da177e4SLinus Torvalds {
24358dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
24368dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
24378dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
243875ad23bcSNick Piggin 	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
24398dea0d02SFUJITA Tomonori 	return 0;
24408dea0d02SFUJITA Tomonori }
24411da177e4SLinus Torvalds 
24428dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
24438dea0d02SFUJITA Tomonori {
24448dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip;
2445a34c4e98SFUJITA Tomonori 
24461da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
24478dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
24488dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
24498dea0d02SFUJITA Tomonori 	if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
24508dea0d02SFUJITA Tomonori 		sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
24518dea0d02SFUJITA Tomonori 	devip = devInfoReg(sdp);
24528dea0d02SFUJITA Tomonori 	if (NULL == devip)
24538dea0d02SFUJITA Tomonori 		return 1;	/* no resources, will be marked offline */
24548dea0d02SFUJITA Tomonori 	sdp->hostdata = devip;
24558dea0d02SFUJITA Tomonori 	if (sdp->host->cmd_per_lun)
24568dea0d02SFUJITA Tomonori 		scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
24578dea0d02SFUJITA Tomonori 					sdp->host->cmd_per_lun);
24588dea0d02SFUJITA Tomonori 	blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
245978d4e5a0SDouglas Gilbert 	if (scsi_debug_no_uld)
246078d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
24618dea0d02SFUJITA Tomonori 	return 0;
24628dea0d02SFUJITA Tomonori }
24638dea0d02SFUJITA Tomonori 
24648dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
24658dea0d02SFUJITA Tomonori {
24668dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
24678dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
24688dea0d02SFUJITA Tomonori 
24698dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
24708dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
24718dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
24728dea0d02SFUJITA Tomonori 	if (devip) {
247325985edcSLucas De Marchi 		/* make this slot available for re-use */
24748dea0d02SFUJITA Tomonori 		devip->used = 0;
24758dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
24768dea0d02SFUJITA Tomonori 	}
24778dea0d02SFUJITA Tomonori }
24788dea0d02SFUJITA Tomonori 
24798dea0d02SFUJITA Tomonori /* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
24808dea0d02SFUJITA Tomonori static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
24818dea0d02SFUJITA Tomonori {
24828dea0d02SFUJITA Tomonori 	unsigned long iflags;
24838dea0d02SFUJITA Tomonori 	int k;
24848dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
24858dea0d02SFUJITA Tomonori 
24868dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
248778d4e5a0SDouglas Gilbert 	for (k = 0; k < scsi_debug_max_queue; ++k) {
24888dea0d02SFUJITA Tomonori 		sqcp = &queued_arr[k];
24898dea0d02SFUJITA Tomonori 		if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
24908dea0d02SFUJITA Tomonori 			del_timer_sync(&sqcp->cmnd_timer);
24918dea0d02SFUJITA Tomonori 			sqcp->in_use = 0;
24928dea0d02SFUJITA Tomonori 			sqcp->a_cmnd = NULL;
24938dea0d02SFUJITA Tomonori 			break;
24948dea0d02SFUJITA Tomonori 		}
24958dea0d02SFUJITA Tomonori 	}
24968dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
249778d4e5a0SDouglas Gilbert 	return (k < scsi_debug_max_queue) ? 1 : 0;
24988dea0d02SFUJITA Tomonori }
24998dea0d02SFUJITA Tomonori 
25008dea0d02SFUJITA Tomonori /* Deletes (stops) timers of all queued commands */
25018dea0d02SFUJITA Tomonori static void stop_all_queued(void)
25028dea0d02SFUJITA Tomonori {
25038dea0d02SFUJITA Tomonori 	unsigned long iflags;
25048dea0d02SFUJITA Tomonori 	int k;
25058dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
25068dea0d02SFUJITA Tomonori 
25078dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
250878d4e5a0SDouglas Gilbert 	for (k = 0; k < scsi_debug_max_queue; ++k) {
25098dea0d02SFUJITA Tomonori 		sqcp = &queued_arr[k];
25108dea0d02SFUJITA Tomonori 		if (sqcp->in_use && sqcp->a_cmnd) {
25118dea0d02SFUJITA Tomonori 			del_timer_sync(&sqcp->cmnd_timer);
25128dea0d02SFUJITA Tomonori 			sqcp->in_use = 0;
25138dea0d02SFUJITA Tomonori 			sqcp->a_cmnd = NULL;
25148dea0d02SFUJITA Tomonori 		}
25158dea0d02SFUJITA Tomonori 	}
25168dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
25171da177e4SLinus Torvalds }
25181da177e4SLinus Torvalds 
25191da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
25201da177e4SLinus Torvalds {
25211da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25221da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: abort\n");
25231da177e4SLinus Torvalds 	++num_aborts;
25241da177e4SLinus Torvalds 	stop_queued_cmnd(SCpnt);
25251da177e4SLinus Torvalds 	return SUCCESS;
25261da177e4SLinus Torvalds }
25271da177e4SLinus Torvalds 
25281da177e4SLinus Torvalds static int scsi_debug_biosparam(struct scsi_device *sdev,
25291da177e4SLinus Torvalds 		struct block_device * bdev, sector_t capacity, int *info)
25301da177e4SLinus Torvalds {
25311da177e4SLinus Torvalds 	int res;
25321da177e4SLinus Torvalds 	unsigned char *buf;
25331da177e4SLinus Torvalds 
25341da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25351da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: biosparam\n");
25361da177e4SLinus Torvalds 	buf = scsi_bios_ptable(bdev);
25371da177e4SLinus Torvalds 	if (buf) {
25381da177e4SLinus Torvalds 		res = scsi_partsize(buf, capacity,
25391da177e4SLinus Torvalds 				    &info[2], &info[0], &info[1]);
25401da177e4SLinus Torvalds 		kfree(buf);
25411da177e4SLinus Torvalds 		if (! res)
25421da177e4SLinus Torvalds 			return res;
25431da177e4SLinus Torvalds 	}
25441da177e4SLinus Torvalds 	info[0] = sdebug_heads;
25451da177e4SLinus Torvalds 	info[1] = sdebug_sectors_per;
25461da177e4SLinus Torvalds 	info[2] = sdebug_cylinders_per;
25471da177e4SLinus Torvalds 	return 0;
25481da177e4SLinus Torvalds }
25491da177e4SLinus Torvalds 
25501da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
25511da177e4SLinus Torvalds {
25521da177e4SLinus Torvalds 	struct sdebug_dev_info * devip;
25531da177e4SLinus Torvalds 
25541da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25551da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: device_reset\n");
25561da177e4SLinus Torvalds 	++num_dev_resets;
25571da177e4SLinus Torvalds 	if (SCpnt) {
25581da177e4SLinus Torvalds 		devip = devInfoReg(SCpnt->device);
25591da177e4SLinus Torvalds 		if (devip)
25601da177e4SLinus Torvalds 			devip->reset = 1;
25611da177e4SLinus Torvalds 	}
25621da177e4SLinus Torvalds 	return SUCCESS;
25631da177e4SLinus Torvalds }
25641da177e4SLinus Torvalds 
25651da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
25661da177e4SLinus Torvalds {
25671da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
25681da177e4SLinus Torvalds         struct sdebug_dev_info * dev_info;
25691da177e4SLinus Torvalds         struct scsi_device * sdp;
25701da177e4SLinus Torvalds         struct Scsi_Host * hp;
25711da177e4SLinus Torvalds 
25721da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25731da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: bus_reset\n");
25741da177e4SLinus Torvalds 	++num_bus_resets;
25751da177e4SLinus Torvalds 	if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
2576d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
25771da177e4SLinus Torvalds 		if (sdbg_host) {
25781da177e4SLinus Torvalds 			list_for_each_entry(dev_info,
25791da177e4SLinus Torvalds                                             &sdbg_host->dev_info_list,
25801da177e4SLinus Torvalds                                             dev_list)
25811da177e4SLinus Torvalds 				dev_info->reset = 1;
25821da177e4SLinus Torvalds 		}
25831da177e4SLinus Torvalds 	}
25841da177e4SLinus Torvalds 	return SUCCESS;
25851da177e4SLinus Torvalds }
25861da177e4SLinus Torvalds 
25871da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
25881da177e4SLinus Torvalds {
25891da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
25901da177e4SLinus Torvalds         struct sdebug_dev_info * dev_info;
25911da177e4SLinus Torvalds 
25921da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25931da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: host_reset\n");
25941da177e4SLinus Torvalds 	++num_host_resets;
25951da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
25961da177e4SLinus Torvalds         list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
25971da177e4SLinus Torvalds                 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
25981da177e4SLinus Torvalds                                     dev_list)
25991da177e4SLinus Torvalds                         dev_info->reset = 1;
26001da177e4SLinus Torvalds         }
26011da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
26021da177e4SLinus Torvalds 	stop_all_queued();
26031da177e4SLinus Torvalds 	return SUCCESS;
26041da177e4SLinus Torvalds }
26051da177e4SLinus Torvalds 
26061da177e4SLinus Torvalds /* Initializes timers in queued array */
26071da177e4SLinus Torvalds static void __init init_all_queued(void)
26081da177e4SLinus Torvalds {
26091da177e4SLinus Torvalds 	unsigned long iflags;
26101da177e4SLinus Torvalds 	int k;
26111da177e4SLinus Torvalds 	struct sdebug_queued_cmd * sqcp;
26121da177e4SLinus Torvalds 
26131da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
261478d4e5a0SDouglas Gilbert 	for (k = 0; k < scsi_debug_max_queue; ++k) {
26151da177e4SLinus Torvalds 		sqcp = &queued_arr[k];
26161da177e4SLinus Torvalds 		init_timer(&sqcp->cmnd_timer);
26171da177e4SLinus Torvalds 		sqcp->in_use = 0;
26181da177e4SLinus Torvalds 		sqcp->a_cmnd = NULL;
26191da177e4SLinus Torvalds 	}
26201da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
26211da177e4SLinus Torvalds }
26221da177e4SLinus Torvalds 
2623f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
26245f2578e5SFUJITA Tomonori 				      unsigned long store_size)
26251da177e4SLinus Torvalds {
26261da177e4SLinus Torvalds 	struct partition * pp;
26271da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
26281da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
26291da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
26301da177e4SLinus Torvalds 
26311da177e4SLinus Torvalds 	/* assume partition table already zeroed */
2632f58b0efbSFUJITA Tomonori 	if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
26331da177e4SLinus Torvalds 		return;
26341da177e4SLinus Torvalds 	if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
26351da177e4SLinus Torvalds 		scsi_debug_num_parts = SDEBUG_MAX_PARTS;
26361da177e4SLinus Torvalds 		printk(KERN_WARNING "scsi_debug:build_parts: reducing "
26371da177e4SLinus Torvalds 				    "partitions to %d\n", SDEBUG_MAX_PARTS);
26381da177e4SLinus Torvalds 	}
2639c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
26401da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
26411da177e4SLinus Torvalds 			   / scsi_debug_num_parts;
26421da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
26431da177e4SLinus Torvalds         starts[0] = sdebug_sectors_per;
26441da177e4SLinus Torvalds 	for (k = 1; k < scsi_debug_num_parts; ++k)
26451da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
26461da177e4SLinus Torvalds 			    * heads_by_sects;
26471da177e4SLinus Torvalds 	starts[scsi_debug_num_parts] = num_sectors;
26481da177e4SLinus Torvalds 	starts[scsi_debug_num_parts + 1] = 0;
26491da177e4SLinus Torvalds 
26501da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
26511da177e4SLinus Torvalds 	ramp[511] = 0xAA;
26521da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
26531da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
26541da177e4SLinus Torvalds 		start_sec = starts[k];
26551da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
26561da177e4SLinus Torvalds 		pp->boot_ind = 0;
26571da177e4SLinus Torvalds 
26581da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
26591da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
26601da177e4SLinus Torvalds 			   / sdebug_sectors_per;
26611da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
26621da177e4SLinus Torvalds 
26631da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
26641da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
26651da177e4SLinus Torvalds 			       / sdebug_sectors_per;
26661da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
26671da177e4SLinus Torvalds 
2668150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
2669150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
26701da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
26711da177e4SLinus Torvalds 	}
26721da177e4SLinus Torvalds }
26731da177e4SLinus Torvalds 
26741da177e4SLinus Torvalds static int schedule_resp(struct scsi_cmnd * cmnd,
26751da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip,
26761da177e4SLinus Torvalds 			 done_funct_t done, int scsi_result, int delta_jiff)
26771da177e4SLinus Torvalds {
26781da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
26791da177e4SLinus Torvalds 		if (scsi_result) {
26801da177e4SLinus Torvalds 			struct scsi_device * sdp = cmnd->device;
26811da177e4SLinus Torvalds 
2682c65b1445SDouglas Gilbert 			printk(KERN_INFO "scsi_debug:    <%u %u %u %u> "
2683c65b1445SDouglas Gilbert 			       "non-zero result=0x%x\n", sdp->host->host_no,
2684c65b1445SDouglas Gilbert 			       sdp->channel, sdp->id, sdp->lun, scsi_result);
26851da177e4SLinus Torvalds 		}
26861da177e4SLinus Torvalds 	}
26871da177e4SLinus Torvalds 	if (cmnd && devip) {
26881da177e4SLinus Torvalds 		/* simulate autosense by this driver */
26891da177e4SLinus Torvalds 		if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
26901da177e4SLinus Torvalds 			memcpy(cmnd->sense_buffer, devip->sense_buff,
26911da177e4SLinus Torvalds 			       (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
26921da177e4SLinus Torvalds 			       SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
26931da177e4SLinus Torvalds 	}
26941da177e4SLinus Torvalds 	if (delta_jiff <= 0) {
26951da177e4SLinus Torvalds 		if (cmnd)
26961da177e4SLinus Torvalds 			cmnd->result = scsi_result;
26971da177e4SLinus Torvalds 		if (done)
26981da177e4SLinus Torvalds 			done(cmnd);
26991da177e4SLinus Torvalds 		return 0;
27001da177e4SLinus Torvalds 	} else {
27011da177e4SLinus Torvalds 		unsigned long iflags;
27021da177e4SLinus Torvalds 		int k;
27031da177e4SLinus Torvalds 		struct sdebug_queued_cmd * sqcp = NULL;
27041da177e4SLinus Torvalds 
27051da177e4SLinus Torvalds 		spin_lock_irqsave(&queued_arr_lock, iflags);
270678d4e5a0SDouglas Gilbert 		for (k = 0; k < scsi_debug_max_queue; ++k) {
27071da177e4SLinus Torvalds 			sqcp = &queued_arr[k];
27081da177e4SLinus Torvalds 			if (! sqcp->in_use)
27091da177e4SLinus Torvalds 				break;
27101da177e4SLinus Torvalds 		}
271178d4e5a0SDouglas Gilbert 		if (k >= scsi_debug_max_queue) {
27121da177e4SLinus Torvalds 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
27131da177e4SLinus Torvalds 			printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
27141da177e4SLinus Torvalds 			return 1;	/* report busy to mid level */
27151da177e4SLinus Torvalds 		}
27161da177e4SLinus Torvalds 		sqcp->in_use = 1;
27171da177e4SLinus Torvalds 		sqcp->a_cmnd = cmnd;
27181da177e4SLinus Torvalds 		sqcp->scsi_result = scsi_result;
27191da177e4SLinus Torvalds 		sqcp->done_funct = done;
27201da177e4SLinus Torvalds 		sqcp->cmnd_timer.function = timer_intr_handler;
27211da177e4SLinus Torvalds 		sqcp->cmnd_timer.data = k;
27221da177e4SLinus Torvalds 		sqcp->cmnd_timer.expires = jiffies + delta_jiff;
27231da177e4SLinus Torvalds 		add_timer(&sqcp->cmnd_timer);
27241da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
27251da177e4SLinus Torvalds 		if (cmnd)
27261da177e4SLinus Torvalds 			cmnd->result = 0;
27271da177e4SLinus Torvalds 		return 0;
27281da177e4SLinus Torvalds 	}
27291da177e4SLinus Torvalds }
273023183910SDouglas Gilbert /* Note: The following macros create attribute files in the
273123183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
273223183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
273323183910SDouglas Gilbert    as it can when the corresponding attribute in the
273423183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
273523183910SDouglas Gilbert  */
2736c65b1445SDouglas Gilbert module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
27375b94e232SMartin K. Petersen module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
2738c65b1445SDouglas Gilbert module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2739c65b1445SDouglas Gilbert module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
27405b94e232SMartin K. Petersen module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
27415b94e232SMartin K. Petersen module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
2742c65b1445SDouglas Gilbert module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2743c65b1445SDouglas Gilbert module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
274423183910SDouglas Gilbert module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
27455b94e232SMartin K. Petersen module_param_named(guard, scsi_debug_guard, int, S_IRUGO);
27465b94e232SMartin K. Petersen module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO);
27475b94e232SMartin K. Petersen module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO);
27485b94e232SMartin K. Petersen module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO);
2749be1dd78dSEric Sandeen module_param_named(lbprz, scsi_debug_lbprz, int, S_IRUGO);
27505b94e232SMartin K. Petersen module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
2751c65b1445SDouglas Gilbert module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
275278d4e5a0SDouglas Gilbert module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);
2753c65b1445SDouglas Gilbert module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
275478d4e5a0SDouglas Gilbert module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);
2755c65b1445SDouglas Gilbert module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2756c65b1445SDouglas Gilbert module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
27575b94e232SMartin K. Petersen module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO);
2758c65b1445SDouglas Gilbert module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
27595b94e232SMartin K. Petersen module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
2760c65b1445SDouglas Gilbert module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2761d986788bSMartin Pitt module_param_named(removable, scsi_debug_removable, bool, S_IRUGO | S_IWUSR);
2762c65b1445SDouglas Gilbert module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
27635b94e232SMartin K. Petersen module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
27645b94e232SMartin K. Petersen module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
27655b94e232SMartin K. Petersen module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
27665b94e232SMartin K. Petersen module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
27675b94e232SMartin K. Petersen module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
2768c65b1445SDouglas Gilbert module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
276923183910SDouglas Gilbert module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
277023183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
27715b94e232SMartin K. Petersen module_param_named(write_same_length, scsi_debug_write_same_length, int,
27725b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
27731da177e4SLinus Torvalds 
27741da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
27751da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
27761da177e4SLinus Torvalds MODULE_LICENSE("GPL");
27771da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION);
27781da177e4SLinus Torvalds 
27791da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
27805b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
27811da177e4SLinus Torvalds MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
2782c65b1445SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
27835b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
27845b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
2785c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
2786beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
278723183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
27885b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
27895b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
27905b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
27915b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
2792be1dd78dSEric Sandeen MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
27935b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
2794c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
279578d4e5a0SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to 255(def))");
2796c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
279778d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
27981da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
2799c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
28005b94e232SMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
28016f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
28025b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
28031da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2804d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
28051da177e4SLinus Torvalds MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
2806ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
28075b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
28085b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
28096014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
28106014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
28115b94e232SMartin K. Petersen MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
28125b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
28135b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
28141da177e4SLinus Torvalds 
28151da177e4SLinus Torvalds static char sdebug_info[256];
28161da177e4SLinus Torvalds 
28171da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp)
28181da177e4SLinus Torvalds {
28191da177e4SLinus Torvalds 	sprintf(sdebug_info, "scsi_debug, version %s [%s], "
28201da177e4SLinus Torvalds 		"dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
28211da177e4SLinus Torvalds 		scsi_debug_version_date, scsi_debug_dev_size_mb,
28221da177e4SLinus Torvalds 		scsi_debug_opts);
28231da177e4SLinus Torvalds 	return sdebug_info;
28241da177e4SLinus Torvalds }
28251da177e4SLinus Torvalds 
28261da177e4SLinus Torvalds /* scsi_debug_proc_info
28271da177e4SLinus Torvalds  * Used if the driver currently has no own support for /proc/scsi
28281da177e4SLinus Torvalds  */
2829c8ed555aSAl Viro static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, int length)
28301da177e4SLinus Torvalds {
28311da177e4SLinus Torvalds 	char arr[16];
2832c8ed555aSAl Viro 	int opts;
28331da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
28341da177e4SLinus Torvalds 
28351da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
28361da177e4SLinus Torvalds 		return -EACCES;
28371da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
28381da177e4SLinus Torvalds 	arr[minLen] = '\0';
2839c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
28401da177e4SLinus Torvalds 		return -EINVAL;
2841c8ed555aSAl Viro 	scsi_debug_opts = opts;
28421da177e4SLinus Torvalds 	if (scsi_debug_every_nth != 0)
28431da177e4SLinus Torvalds 		scsi_debug_cmnd_count = 0;
28441da177e4SLinus Torvalds 	return length;
28451da177e4SLinus Torvalds }
2846c8ed555aSAl Viro 
2847c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
2848c8ed555aSAl Viro {
2849c8ed555aSAl Viro 	seq_printf(m, "scsi_debug adapter driver, version "
28501da177e4SLinus Torvalds 	    "%s [%s]\n"
28511da177e4SLinus Torvalds 	    "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
28521da177e4SLinus Torvalds 	    "every_nth=%d(curr:%d)\n"
28531da177e4SLinus Torvalds 	    "delay=%d, max_luns=%d, scsi_level=%d\n"
28541da177e4SLinus Torvalds 	    "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
28551da177e4SLinus Torvalds 	    "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2856c6a44287SMartin K. Petersen 	    "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n",
28571da177e4SLinus Torvalds 	    SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
28581da177e4SLinus Torvalds 	    scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
28591da177e4SLinus Torvalds 	    scsi_debug_cmnd_count, scsi_debug_delay,
28601da177e4SLinus Torvalds 	    scsi_debug_max_luns, scsi_debug_scsi_level,
2861597136abSMartin K. Petersen 	    scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
2862597136abSMartin K. Petersen 	    sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
2863c6a44287SMartin K. Petersen 	    num_host_resets, dix_reads, dix_writes, dif_errors);
2864c8ed555aSAl Viro 	return 0;
28651da177e4SLinus Torvalds }
28661da177e4SLinus Torvalds 
28671da177e4SLinus Torvalds static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
28681da177e4SLinus Torvalds {
28691da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
28701da177e4SLinus Torvalds }
28711da177e4SLinus Torvalds 
28721da177e4SLinus Torvalds static ssize_t sdebug_delay_store(struct device_driver * ddp,
28731da177e4SLinus Torvalds 				  const char * buf, size_t count)
28741da177e4SLinus Torvalds {
28751da177e4SLinus Torvalds         int delay;
28761da177e4SLinus Torvalds 	char work[20];
28771da177e4SLinus Torvalds 
28781da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
28791da177e4SLinus Torvalds 		if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
28801da177e4SLinus Torvalds 			scsi_debug_delay = delay;
28811da177e4SLinus Torvalds 			return count;
28821da177e4SLinus Torvalds 		}
28831da177e4SLinus Torvalds 	}
28841da177e4SLinus Torvalds 	return -EINVAL;
28851da177e4SLinus Torvalds }
28861da177e4SLinus Torvalds DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
28871da177e4SLinus Torvalds 	    sdebug_delay_store);
28881da177e4SLinus Torvalds 
28891da177e4SLinus Torvalds static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
28901da177e4SLinus Torvalds {
28911da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
28921da177e4SLinus Torvalds }
28931da177e4SLinus Torvalds 
28941da177e4SLinus Torvalds static ssize_t sdebug_opts_store(struct device_driver * ddp,
28951da177e4SLinus Torvalds 				 const char * buf, size_t count)
28961da177e4SLinus Torvalds {
28971da177e4SLinus Torvalds         int opts;
28981da177e4SLinus Torvalds 	char work[20];
28991da177e4SLinus Torvalds 
29001da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
29011da177e4SLinus Torvalds 		if (0 == strnicmp(work,"0x", 2)) {
29021da177e4SLinus Torvalds 			if (1 == sscanf(&work[2], "%x", &opts))
29031da177e4SLinus Torvalds 				goto opts_done;
29041da177e4SLinus Torvalds 		} else {
29051da177e4SLinus Torvalds 			if (1 == sscanf(work, "%d", &opts))
29061da177e4SLinus Torvalds 				goto opts_done;
29071da177e4SLinus Torvalds 		}
29081da177e4SLinus Torvalds 	}
29091da177e4SLinus Torvalds 	return -EINVAL;
29101da177e4SLinus Torvalds opts_done:
29111da177e4SLinus Torvalds 	scsi_debug_opts = opts;
29121da177e4SLinus Torvalds 	scsi_debug_cmnd_count = 0;
29131da177e4SLinus Torvalds 	return count;
29141da177e4SLinus Torvalds }
29151da177e4SLinus Torvalds DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
29161da177e4SLinus Torvalds 	    sdebug_opts_store);
29171da177e4SLinus Torvalds 
29181da177e4SLinus Torvalds static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
29191da177e4SLinus Torvalds {
29201da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
29211da177e4SLinus Torvalds }
29221da177e4SLinus Torvalds static ssize_t sdebug_ptype_store(struct device_driver * ddp,
29231da177e4SLinus Torvalds 				  const char * buf, size_t count)
29241da177e4SLinus Torvalds {
29251da177e4SLinus Torvalds         int n;
29261da177e4SLinus Torvalds 
29271da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
29281da177e4SLinus Torvalds 		scsi_debug_ptype = n;
29291da177e4SLinus Torvalds 		return count;
29301da177e4SLinus Torvalds 	}
29311da177e4SLinus Torvalds 	return -EINVAL;
29321da177e4SLinus Torvalds }
29331da177e4SLinus Torvalds DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
29341da177e4SLinus Torvalds 
29351da177e4SLinus Torvalds static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
29361da177e4SLinus Torvalds {
29371da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
29381da177e4SLinus Torvalds }
29391da177e4SLinus Torvalds static ssize_t sdebug_dsense_store(struct device_driver * ddp,
29401da177e4SLinus Torvalds 				  const char * buf, size_t count)
29411da177e4SLinus Torvalds {
29421da177e4SLinus Torvalds         int n;
29431da177e4SLinus Torvalds 
29441da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
29451da177e4SLinus Torvalds 		scsi_debug_dsense = n;
29461da177e4SLinus Torvalds 		return count;
29471da177e4SLinus Torvalds 	}
29481da177e4SLinus Torvalds 	return -EINVAL;
29491da177e4SLinus Torvalds }
29501da177e4SLinus Torvalds DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
29511da177e4SLinus Torvalds 	    sdebug_dsense_store);
29521da177e4SLinus Torvalds 
295323183910SDouglas Gilbert static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
295423183910SDouglas Gilbert {
295523183910SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
295623183910SDouglas Gilbert }
295723183910SDouglas Gilbert static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
295823183910SDouglas Gilbert 				    const char * buf, size_t count)
295923183910SDouglas Gilbert {
296023183910SDouglas Gilbert         int n;
296123183910SDouglas Gilbert 
296223183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
296323183910SDouglas Gilbert 		scsi_debug_fake_rw = n;
296423183910SDouglas Gilbert 		return count;
296523183910SDouglas Gilbert 	}
296623183910SDouglas Gilbert 	return -EINVAL;
296723183910SDouglas Gilbert }
296823183910SDouglas Gilbert DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
296923183910SDouglas Gilbert 	    sdebug_fake_rw_store);
297023183910SDouglas Gilbert 
2971c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2972c65b1445SDouglas Gilbert {
2973c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2974c65b1445SDouglas Gilbert }
2975c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2976c65b1445SDouglas Gilbert 				     const char * buf, size_t count)
2977c65b1445SDouglas Gilbert {
2978c65b1445SDouglas Gilbert         int n;
2979c65b1445SDouglas Gilbert 
2980c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2981c65b1445SDouglas Gilbert 		scsi_debug_no_lun_0 = n;
2982c65b1445SDouglas Gilbert 		return count;
2983c65b1445SDouglas Gilbert 	}
2984c65b1445SDouglas Gilbert 	return -EINVAL;
2985c65b1445SDouglas Gilbert }
2986c65b1445SDouglas Gilbert DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2987c65b1445SDouglas Gilbert 	    sdebug_no_lun_0_store);
2988c65b1445SDouglas Gilbert 
29891da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
29901da177e4SLinus Torvalds {
29911da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
29921da177e4SLinus Torvalds }
29931da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
29941da177e4SLinus Torvalds 				     const char * buf, size_t count)
29951da177e4SLinus Torvalds {
29961da177e4SLinus Torvalds         int n;
29971da177e4SLinus Torvalds 
29981da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
29991da177e4SLinus Torvalds 		scsi_debug_num_tgts = n;
30001da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
30011da177e4SLinus Torvalds 		return count;
30021da177e4SLinus Torvalds 	}
30031da177e4SLinus Torvalds 	return -EINVAL;
30041da177e4SLinus Torvalds }
30051da177e4SLinus Torvalds DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
30061da177e4SLinus Torvalds 	    sdebug_num_tgts_store);
30071da177e4SLinus Torvalds 
30081da177e4SLinus Torvalds static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
30091da177e4SLinus Torvalds {
30101da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
30111da177e4SLinus Torvalds }
30121da177e4SLinus Torvalds DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
30131da177e4SLinus Torvalds 
30141da177e4SLinus Torvalds static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
30151da177e4SLinus Torvalds {
30161da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
30171da177e4SLinus Torvalds }
30181da177e4SLinus Torvalds DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
30191da177e4SLinus Torvalds 
30201da177e4SLinus Torvalds static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
30211da177e4SLinus Torvalds {
30221da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
30231da177e4SLinus Torvalds }
30241da177e4SLinus Torvalds static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
30251da177e4SLinus Torvalds 				      const char * buf, size_t count)
30261da177e4SLinus Torvalds {
30271da177e4SLinus Torvalds         int nth;
30281da177e4SLinus Torvalds 
30291da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
30301da177e4SLinus Torvalds 		scsi_debug_every_nth = nth;
30311da177e4SLinus Torvalds 		scsi_debug_cmnd_count = 0;
30321da177e4SLinus Torvalds 		return count;
30331da177e4SLinus Torvalds 	}
30341da177e4SLinus Torvalds 	return -EINVAL;
30351da177e4SLinus Torvalds }
30361da177e4SLinus Torvalds DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
30371da177e4SLinus Torvalds 	    sdebug_every_nth_store);
30381da177e4SLinus Torvalds 
30391da177e4SLinus Torvalds static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
30401da177e4SLinus Torvalds {
30411da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
30421da177e4SLinus Torvalds }
30431da177e4SLinus Torvalds static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
30441da177e4SLinus Torvalds 				     const char * buf, size_t count)
30451da177e4SLinus Torvalds {
30461da177e4SLinus Torvalds         int n;
30471da177e4SLinus Torvalds 
30481da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
30491da177e4SLinus Torvalds 		scsi_debug_max_luns = n;
30501da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
30511da177e4SLinus Torvalds 		return count;
30521da177e4SLinus Torvalds 	}
30531da177e4SLinus Torvalds 	return -EINVAL;
30541da177e4SLinus Torvalds }
30551da177e4SLinus Torvalds DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
30561da177e4SLinus Torvalds 	    sdebug_max_luns_store);
30571da177e4SLinus Torvalds 
305878d4e5a0SDouglas Gilbert static ssize_t sdebug_max_queue_show(struct device_driver * ddp, char * buf)
305978d4e5a0SDouglas Gilbert {
306078d4e5a0SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue);
306178d4e5a0SDouglas Gilbert }
306278d4e5a0SDouglas Gilbert static ssize_t sdebug_max_queue_store(struct device_driver * ddp,
306378d4e5a0SDouglas Gilbert 				      const char * buf, size_t count)
306478d4e5a0SDouglas Gilbert {
306578d4e5a0SDouglas Gilbert         int n;
306678d4e5a0SDouglas Gilbert 
306778d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
306878d4e5a0SDouglas Gilbert 	    (n <= SCSI_DEBUG_CANQUEUE)) {
306978d4e5a0SDouglas Gilbert 		scsi_debug_max_queue = n;
307078d4e5a0SDouglas Gilbert 		return count;
307178d4e5a0SDouglas Gilbert 	}
307278d4e5a0SDouglas Gilbert 	return -EINVAL;
307378d4e5a0SDouglas Gilbert }
307478d4e5a0SDouglas Gilbert DRIVER_ATTR(max_queue, S_IRUGO | S_IWUSR, sdebug_max_queue_show,
307578d4e5a0SDouglas Gilbert 	    sdebug_max_queue_store);
307678d4e5a0SDouglas Gilbert 
307778d4e5a0SDouglas Gilbert static ssize_t sdebug_no_uld_show(struct device_driver * ddp, char * buf)
307878d4e5a0SDouglas Gilbert {
307978d4e5a0SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld);
308078d4e5a0SDouglas Gilbert }
308178d4e5a0SDouglas Gilbert DRIVER_ATTR(no_uld, S_IRUGO, sdebug_no_uld_show, NULL);
308278d4e5a0SDouglas Gilbert 
30831da177e4SLinus Torvalds static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
30841da177e4SLinus Torvalds {
30851da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
30861da177e4SLinus Torvalds }
30871da177e4SLinus Torvalds DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
30881da177e4SLinus Torvalds 
3089c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
3090c65b1445SDouglas Gilbert {
3091c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
3092c65b1445SDouglas Gilbert }
3093c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
3094c65b1445SDouglas Gilbert 				       const char * buf, size_t count)
3095c65b1445SDouglas Gilbert {
3096c65b1445SDouglas Gilbert         int n;
3097c65b1445SDouglas Gilbert 
3098c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3099c65b1445SDouglas Gilbert 		scsi_debug_virtual_gb = n;
310028898873SFUJITA Tomonori 
310128898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
310228898873SFUJITA Tomonori 
3103c65b1445SDouglas Gilbert 		return count;
3104c65b1445SDouglas Gilbert 	}
3105c65b1445SDouglas Gilbert 	return -EINVAL;
3106c65b1445SDouglas Gilbert }
3107c65b1445SDouglas Gilbert DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
3108c65b1445SDouglas Gilbert 	    sdebug_virtual_gb_store);
3109c65b1445SDouglas Gilbert 
31101da177e4SLinus Torvalds static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
31111da177e4SLinus Torvalds {
31121da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
31131da177e4SLinus Torvalds }
31141da177e4SLinus Torvalds 
31151da177e4SLinus Torvalds static ssize_t sdebug_add_host_store(struct device_driver * ddp,
31161da177e4SLinus Torvalds 				     const char * buf, size_t count)
31171da177e4SLinus Torvalds {
31181da177e4SLinus Torvalds 	int delta_hosts;
31191da177e4SLinus Torvalds 
3120f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
31211da177e4SLinus Torvalds 		return -EINVAL;
31221da177e4SLinus Torvalds 	if (delta_hosts > 0) {
31231da177e4SLinus Torvalds 		do {
31241da177e4SLinus Torvalds 			sdebug_add_adapter();
31251da177e4SLinus Torvalds 		} while (--delta_hosts);
31261da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
31271da177e4SLinus Torvalds 		do {
31281da177e4SLinus Torvalds 			sdebug_remove_adapter();
31291da177e4SLinus Torvalds 		} while (++delta_hosts);
31301da177e4SLinus Torvalds 	}
31311da177e4SLinus Torvalds 	return count;
31321da177e4SLinus Torvalds }
31331da177e4SLinus Torvalds DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
31341da177e4SLinus Torvalds 	    sdebug_add_host_store);
31351da177e4SLinus Torvalds 
313623183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
313723183910SDouglas Gilbert 					  char * buf)
313823183910SDouglas Gilbert {
313923183910SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
314023183910SDouglas Gilbert }
314123183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
314223183910SDouglas Gilbert 					   const char * buf, size_t count)
314323183910SDouglas Gilbert {
314423183910SDouglas Gilbert 	int n;
314523183910SDouglas Gilbert 
314623183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
314723183910SDouglas Gilbert 		scsi_debug_vpd_use_hostno = n;
314823183910SDouglas Gilbert 		return count;
314923183910SDouglas Gilbert 	}
315023183910SDouglas Gilbert 	return -EINVAL;
315123183910SDouglas Gilbert }
315223183910SDouglas Gilbert DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
315323183910SDouglas Gilbert 	    sdebug_vpd_use_hostno_store);
315423183910SDouglas Gilbert 
3155597136abSMartin K. Petersen static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf)
3156597136abSMartin K. Petersen {
3157597136abSMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
3158597136abSMartin K. Petersen }
3159597136abSMartin K. Petersen DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL);
3160597136abSMartin K. Petersen 
3161c6a44287SMartin K. Petersen static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf)
3162c6a44287SMartin K. Petersen {
3163c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
3164c6a44287SMartin K. Petersen }
3165c6a44287SMartin K. Petersen DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL);
3166c6a44287SMartin K. Petersen 
3167c6a44287SMartin K. Petersen static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf)
3168c6a44287SMartin K. Petersen {
3169c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
3170c6a44287SMartin K. Petersen }
3171c6a44287SMartin K. Petersen DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL);
3172c6a44287SMartin K. Petersen 
3173c6a44287SMartin K. Petersen static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf)
3174c6a44287SMartin K. Petersen {
3175c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard);
3176c6a44287SMartin K. Petersen }
3177c6a44287SMartin K. Petersen DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL);
3178c6a44287SMartin K. Petersen 
3179c6a44287SMartin K. Petersen static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf)
3180c6a44287SMartin K. Petersen {
3181c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
3182c6a44287SMartin K. Petersen }
3183c6a44287SMartin K. Petersen DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL);
3184c6a44287SMartin K. Petersen 
318544d92694SMartin K. Petersen static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf)
318644d92694SMartin K. Petersen {
318744d92694SMartin K. Petersen 	ssize_t count;
318844d92694SMartin K. Petersen 
31895b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
319044d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
319144d92694SMartin K. Petersen 				 sdebug_store_sectors);
319244d92694SMartin K. Petersen 
319344d92694SMartin K. Petersen 	count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
319444d92694SMartin K. Petersen 
319544d92694SMartin K. Petersen 	buf[count++] = '\n';
319644d92694SMartin K. Petersen 	buf[count++] = 0;
319744d92694SMartin K. Petersen 
319844d92694SMartin K. Petersen 	return count;
319944d92694SMartin K. Petersen }
320044d92694SMartin K. Petersen DRIVER_ATTR(map, S_IRUGO, sdebug_map_show, NULL);
320144d92694SMartin K. Petersen 
3202d986788bSMartin Pitt static ssize_t sdebug_removable_show(struct device_driver *ddp,
3203d986788bSMartin Pitt 				     char *buf)
3204d986788bSMartin Pitt {
3205d986788bSMartin Pitt 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_removable ? 1 : 0);
3206d986788bSMartin Pitt }
3207d986788bSMartin Pitt static ssize_t sdebug_removable_store(struct device_driver *ddp,
3208d986788bSMartin Pitt 				      const char *buf, size_t count)
3209d986788bSMartin Pitt {
3210d986788bSMartin Pitt 	int n;
3211d986788bSMartin Pitt 
3212d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3213d986788bSMartin Pitt 		scsi_debug_removable = (n > 0);
3214d986788bSMartin Pitt 		return count;
3215d986788bSMartin Pitt 	}
3216d986788bSMartin Pitt 	return -EINVAL;
3217d986788bSMartin Pitt }
3218d986788bSMartin Pitt DRIVER_ATTR(removable, S_IRUGO | S_IWUSR, sdebug_removable_show,
3219d986788bSMartin Pitt 	    sdebug_removable_store);
3220d986788bSMartin Pitt 
3221c6a44287SMartin K. Petersen 
322223183910SDouglas Gilbert /* Note: The following function creates attribute files in the
322323183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
322423183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
322523183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
322623183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
322723183910SDouglas Gilbert  */
32286ecaff7fSRandy Dunlap static int do_create_driverfs_files(void)
32291da177e4SLinus Torvalds {
32306ecaff7fSRandy Dunlap 	int ret;
32316ecaff7fSRandy Dunlap 
32326ecaff7fSRandy Dunlap 	ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
32336ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
32346ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
32356ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
32366ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
323723183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
32386ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
323978d4e5a0SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_queue);
324023183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
324178d4e5a0SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_uld);
32426ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
324323183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
32446ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
32456ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
3246d986788bSMartin Pitt 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_removable);
32476ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
324823183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
324923183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
3250597136abSMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
3251c6a44287SMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix);
3252c6a44287SMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif);
3253c6a44287SMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard);
3254c6a44287SMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato);
325544d92694SMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_map);
32566ecaff7fSRandy Dunlap 	return ret;
32571da177e4SLinus Torvalds }
32581da177e4SLinus Torvalds 
32591da177e4SLinus Torvalds static void do_remove_driverfs_files(void)
32601da177e4SLinus Torvalds {
326144d92694SMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_map);
3262c6a44287SMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato);
3263c6a44287SMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard);
3264c6a44287SMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif);
3265c6a44287SMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix);
3266597136abSMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
326723183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
326823183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
32691da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
32701da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
32711da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
3272d986788bSMartin Pitt 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_removable);
32731da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
327423183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
327578d4e5a0SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_uld);
327623183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
327778d4e5a0SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_queue);
32781da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
327923183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
32801da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
32811da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
32821da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
32831da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
32841da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
32851da177e4SLinus Torvalds }
32861da177e4SLinus Torvalds 
32879b906779SNicholas Bellinger struct device *pseudo_primary;
32888dea0d02SFUJITA Tomonori 
32891da177e4SLinus Torvalds static int __init scsi_debug_init(void)
32901da177e4SLinus Torvalds {
32915f2578e5SFUJITA Tomonori 	unsigned long sz;
32921da177e4SLinus Torvalds 	int host_to_add;
32931da177e4SLinus Torvalds 	int k;
32946ecaff7fSRandy Dunlap 	int ret;
32951da177e4SLinus Torvalds 
3296597136abSMartin K. Petersen 	switch (scsi_debug_sector_size) {
3297597136abSMartin K. Petersen 	case  512:
3298597136abSMartin K. Petersen 	case 1024:
3299597136abSMartin K. Petersen 	case 2048:
3300597136abSMartin K. Petersen 	case 4096:
3301597136abSMartin K. Petersen 		break;
3302597136abSMartin K. Petersen 	default:
3303c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n",
3304597136abSMartin K. Petersen 		       scsi_debug_sector_size);
3305597136abSMartin K. Petersen 		return -EINVAL;
3306597136abSMartin K. Petersen 	}
3307597136abSMartin K. Petersen 
3308c6a44287SMartin K. Petersen 	switch (scsi_debug_dif) {
3309c6a44287SMartin K. Petersen 
3310c6a44287SMartin K. Petersen 	case SD_DIF_TYPE0_PROTECTION:
3311c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
3312395cef03SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
3313c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
3314c6a44287SMartin K. Petersen 		break;
3315c6a44287SMartin K. Petersen 
3316c6a44287SMartin K. Petersen 	default:
3317395cef03SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n");
3318c6a44287SMartin K. Petersen 		return -EINVAL;
3319c6a44287SMartin K. Petersen 	}
3320c6a44287SMartin K. Petersen 
3321c6a44287SMartin K. Petersen 	if (scsi_debug_guard > 1) {
3322c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n");
3323c6a44287SMartin K. Petersen 		return -EINVAL;
3324c6a44287SMartin K. Petersen 	}
3325c6a44287SMartin K. Petersen 
3326c6a44287SMartin K. Petersen 	if (scsi_debug_ato > 1) {
3327c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n");
3328c6a44287SMartin K. Petersen 		return -EINVAL;
3329c6a44287SMartin K. Petersen 	}
3330c6a44287SMartin K. Petersen 
3331ea61fca5SMartin K. Petersen 	if (scsi_debug_physblk_exp > 15) {
3332ea61fca5SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n",
3333ea61fca5SMartin K. Petersen 		       scsi_debug_physblk_exp);
3334ea61fca5SMartin K. Petersen 		return -EINVAL;
3335ea61fca5SMartin K. Petersen 	}
3336ea61fca5SMartin K. Petersen 
3337ea61fca5SMartin K. Petersen 	if (scsi_debug_lowest_aligned > 0x3fff) {
3338ea61fca5SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n",
3339ea61fca5SMartin K. Petersen 		       scsi_debug_lowest_aligned);
3340ea61fca5SMartin K. Petersen 		return -EINVAL;
3341ea61fca5SMartin K. Petersen 	}
3342ea61fca5SMartin K. Petersen 
33431da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb < 1)
33441da177e4SLinus Torvalds 		scsi_debug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
33455f2578e5SFUJITA Tomonori 	sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
3346597136abSMartin K. Petersen 	sdebug_store_sectors = sz / scsi_debug_sector_size;
334728898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
33481da177e4SLinus Torvalds 
33491da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
33501da177e4SLinus Torvalds 	sdebug_heads = 8;
33511da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
33521da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb >= 16)
33531da177e4SLinus Torvalds 		sdebug_heads = 32;
33541da177e4SLinus Torvalds 	else if (scsi_debug_dev_size_mb >= 256)
33551da177e4SLinus Torvalds 		sdebug_heads = 64;
33561da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
33571da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
33581da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
33591da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
33601da177e4SLinus Torvalds 		sdebug_heads = 255;
33611da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
33621da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
33631da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
33641da177e4SLinus Torvalds 	}
33651da177e4SLinus Torvalds 
33661da177e4SLinus Torvalds 	fake_storep = vmalloc(sz);
33671da177e4SLinus Torvalds 	if (NULL == fake_storep) {
33681da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
33691da177e4SLinus Torvalds 		return -ENOMEM;
33701da177e4SLinus Torvalds 	}
33711da177e4SLinus Torvalds 	memset(fake_storep, 0, sz);
33721da177e4SLinus Torvalds 	if (scsi_debug_num_parts > 0)
3373f58b0efbSFUJITA Tomonori 		sdebug_build_parts(fake_storep, sz);
33741da177e4SLinus Torvalds 
33757cb69d03SAkinobu Mita 	if (scsi_debug_dix) {
3376c6a44287SMartin K. Petersen 		int dif_size;
3377c6a44287SMartin K. Petersen 
3378c6a44287SMartin K. Petersen 		dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
3379c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
3380c6a44287SMartin K. Petersen 
3381c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n",
3382c6a44287SMartin K. Petersen 		       dif_size, dif_storep);
3383c6a44287SMartin K. Petersen 
3384c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
3385c6a44287SMartin K. Petersen 			printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n");
3386c6a44287SMartin K. Petersen 			ret = -ENOMEM;
3387c6a44287SMartin K. Petersen 			goto free_vm;
3388c6a44287SMartin K. Petersen 		}
3389c6a44287SMartin K. Petersen 
3390c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
3391c6a44287SMartin K. Petersen 	}
3392c6a44287SMartin K. Petersen 
33935b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
33945b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
33956014759cSMartin K. Petersen 		scsi_debug_unmap_max_blocks =
33966014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU);
33976014759cSMartin K. Petersen 
33986014759cSMartin K. Petersen 		scsi_debug_unmap_max_desc =
33996014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_max_desc, 0U, 256U);
34006014759cSMartin K. Petersen 
34016014759cSMartin K. Petersen 		scsi_debug_unmap_granularity =
34026014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU);
34036014759cSMartin K. Petersen 
34046014759cSMartin K. Petersen 		if (scsi_debug_unmap_alignment &&
3405ac17078aSAkinobu Mita 		    scsi_debug_unmap_granularity <=
3406ac17078aSAkinobu Mita 		    scsi_debug_unmap_alignment) {
340744d92694SMartin K. Petersen 			printk(KERN_ERR
3408ac17078aSAkinobu Mita 			       "%s: ERR: unmap_granularity <= unmap_alignment\n",
340944d92694SMartin K. Petersen 			       __func__);
341044d92694SMartin K. Petersen 			return -EINVAL;
341144d92694SMartin K. Petersen 		}
341244d92694SMartin K. Petersen 
3413b90ebc3dSAkinobu Mita 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
3414b90ebc3dSAkinobu Mita 		map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
341544d92694SMartin K. Petersen 
341644d92694SMartin K. Petersen 		printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n",
341744d92694SMartin K. Petersen 		       map_size);
341844d92694SMartin K. Petersen 
341944d92694SMartin K. Petersen 		if (map_storep == NULL) {
342044d92694SMartin K. Petersen 			printk(KERN_ERR "scsi_debug_init: out of mem. (MAP)\n");
342144d92694SMartin K. Petersen 			ret = -ENOMEM;
342244d92694SMartin K. Petersen 			goto free_vm;
342344d92694SMartin K. Petersen 		}
342444d92694SMartin K. Petersen 
3425b90ebc3dSAkinobu Mita 		bitmap_zero(map_storep, map_size);
342644d92694SMartin K. Petersen 
342744d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
342844d92694SMartin K. Petersen 		if (scsi_debug_num_parts)
342944d92694SMartin K. Petersen 			map_region(0, 2);
343044d92694SMartin K. Petersen 	}
343144d92694SMartin K. Petersen 
34329b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
34339b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
34349b906779SNicholas Bellinger 		printk(KERN_WARNING "scsi_debug: root_device_register() error\n");
34359b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
34366ecaff7fSRandy Dunlap 		goto free_vm;
34376ecaff7fSRandy Dunlap 	}
34386ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
34396ecaff7fSRandy Dunlap 	if (ret < 0) {
34406ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
34416ecaff7fSRandy Dunlap 			ret);
34426ecaff7fSRandy Dunlap 		goto dev_unreg;
34436ecaff7fSRandy Dunlap 	}
34446ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
34456ecaff7fSRandy Dunlap 	if (ret < 0) {
34466ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
34476ecaff7fSRandy Dunlap 			ret);
34486ecaff7fSRandy Dunlap 		goto bus_unreg;
34496ecaff7fSRandy Dunlap 	}
34506ecaff7fSRandy Dunlap 	ret = do_create_driverfs_files();
34516ecaff7fSRandy Dunlap 	if (ret < 0) {
34526ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
34536ecaff7fSRandy Dunlap 			ret);
34546ecaff7fSRandy Dunlap 		goto del_files;
34556ecaff7fSRandy Dunlap 	}
34561da177e4SLinus Torvalds 
34576ecaff7fSRandy Dunlap 	init_all_queued();
34581da177e4SLinus Torvalds 
34591da177e4SLinus Torvalds 	host_to_add = scsi_debug_add_host;
34601da177e4SLinus Torvalds         scsi_debug_add_host = 0;
34611da177e4SLinus Torvalds 
34621da177e4SLinus Torvalds         for (k = 0; k < host_to_add; k++) {
34631da177e4SLinus Torvalds                 if (sdebug_add_adapter()) {
34641da177e4SLinus Torvalds                         printk(KERN_ERR "scsi_debug_init: "
34651da177e4SLinus Torvalds                                "sdebug_add_adapter failed k=%d\n", k);
34661da177e4SLinus Torvalds                         break;
34671da177e4SLinus Torvalds                 }
34681da177e4SLinus Torvalds         }
34691da177e4SLinus Torvalds 
34701da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
34711da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
34721da177e4SLinus Torvalds 		       scsi_debug_add_host);
34731da177e4SLinus Torvalds 	}
34741da177e4SLinus Torvalds 	return 0;
34756ecaff7fSRandy Dunlap 
34766ecaff7fSRandy Dunlap del_files:
34776ecaff7fSRandy Dunlap 	do_remove_driverfs_files();
34786ecaff7fSRandy Dunlap 	driver_unregister(&sdebug_driverfs_driver);
34796ecaff7fSRandy Dunlap bus_unreg:
34806ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
34816ecaff7fSRandy Dunlap dev_unreg:
34829b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
34836ecaff7fSRandy Dunlap free_vm:
348444d92694SMartin K. Petersen 	if (map_storep)
348544d92694SMartin K. Petersen 		vfree(map_storep);
3486c6a44287SMartin K. Petersen 	if (dif_storep)
3487c6a44287SMartin K. Petersen 		vfree(dif_storep);
34886ecaff7fSRandy Dunlap 	vfree(fake_storep);
34896ecaff7fSRandy Dunlap 
34906ecaff7fSRandy Dunlap 	return ret;
34911da177e4SLinus Torvalds }
34921da177e4SLinus Torvalds 
34931da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
34941da177e4SLinus Torvalds {
34951da177e4SLinus Torvalds 	int k = scsi_debug_add_host;
34961da177e4SLinus Torvalds 
34971da177e4SLinus Torvalds 	stop_all_queued();
34981da177e4SLinus Torvalds 	for (; k; k--)
34991da177e4SLinus Torvalds 		sdebug_remove_adapter();
35001da177e4SLinus Torvalds 	do_remove_driverfs_files();
35011da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
35021da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
35039b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
35041da177e4SLinus Torvalds 
3505c6a44287SMartin K. Petersen 	if (dif_storep)
3506c6a44287SMartin K. Petersen 		vfree(dif_storep);
3507c6a44287SMartin K. Petersen 
35081da177e4SLinus Torvalds 	vfree(fake_storep);
35091da177e4SLinus Torvalds }
35101da177e4SLinus Torvalds 
35111da177e4SLinus Torvalds device_initcall(scsi_debug_init);
35121da177e4SLinus Torvalds module_exit(scsi_debug_exit);
35131da177e4SLinus Torvalds 
35141da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev)
35151da177e4SLinus Torvalds {
35161da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
35171da177e4SLinus Torvalds 
35181da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
35191da177e4SLinus Torvalds         kfree(sdbg_host);
35201da177e4SLinus Torvalds }
35211da177e4SLinus Torvalds 
35221da177e4SLinus Torvalds static int sdebug_add_adapter(void)
35231da177e4SLinus Torvalds {
35241da177e4SLinus Torvalds 	int k, devs_per_host;
35251da177e4SLinus Torvalds         int error = 0;
35261da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
35278b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
35281da177e4SLinus Torvalds 
352924669f75SJes Sorensen         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
35301da177e4SLinus Torvalds         if (NULL == sdbg_host) {
35311da177e4SLinus Torvalds                 printk(KERN_ERR "%s: out of memory at line %d\n",
3532cadbd4a5SHarvey Harrison                        __func__, __LINE__);
35331da177e4SLinus Torvalds                 return -ENOMEM;
35341da177e4SLinus Torvalds         }
35351da177e4SLinus Torvalds 
35361da177e4SLinus Torvalds         INIT_LIST_HEAD(&sdbg_host->dev_info_list);
35371da177e4SLinus Torvalds 
35381da177e4SLinus Torvalds 	devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
35391da177e4SLinus Torvalds         for (k = 0; k < devs_per_host; k++) {
35405cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
35415cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
35421da177e4SLinus Torvalds                         printk(KERN_ERR "%s: out of memory at line %d\n",
3543cadbd4a5SHarvey Harrison                                __func__, __LINE__);
35441da177e4SLinus Torvalds                         error = -ENOMEM;
35451da177e4SLinus Torvalds 			goto clean;
35461da177e4SLinus Torvalds                 }
35471da177e4SLinus Torvalds         }
35481da177e4SLinus Torvalds 
35491da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
35501da177e4SLinus Torvalds         list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
35511da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
35521da177e4SLinus Torvalds 
35531da177e4SLinus Torvalds         sdbg_host->dev.bus = &pseudo_lld_bus;
35549b906779SNicholas Bellinger         sdbg_host->dev.parent = pseudo_primary;
35551da177e4SLinus Torvalds         sdbg_host->dev.release = &sdebug_release_adapter;
355671610f55SKay Sievers         dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
35571da177e4SLinus Torvalds 
35581da177e4SLinus Torvalds         error = device_register(&sdbg_host->dev);
35591da177e4SLinus Torvalds 
35601da177e4SLinus Torvalds         if (error)
35611da177e4SLinus Torvalds 		goto clean;
35621da177e4SLinus Torvalds 
35631da177e4SLinus Torvalds 	++scsi_debug_add_host;
35641da177e4SLinus Torvalds         return error;
35651da177e4SLinus Torvalds 
35661da177e4SLinus Torvalds clean:
35678b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
35688b40228fSFUJITA Tomonori 				 dev_list) {
35691da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
35701da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
35711da177e4SLinus Torvalds 	}
35721da177e4SLinus Torvalds 
35731da177e4SLinus Torvalds 	kfree(sdbg_host);
35741da177e4SLinus Torvalds         return error;
35751da177e4SLinus Torvalds }
35761da177e4SLinus Torvalds 
35771da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
35781da177e4SLinus Torvalds {
35791da177e4SLinus Torvalds         struct sdebug_host_info * sdbg_host = NULL;
35801da177e4SLinus Torvalds 
35811da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
35821da177e4SLinus Torvalds         if (!list_empty(&sdebug_host_list)) {
35831da177e4SLinus Torvalds                 sdbg_host = list_entry(sdebug_host_list.prev,
35841da177e4SLinus Torvalds                                        struct sdebug_host_info, host_list);
35851da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
35861da177e4SLinus Torvalds 	}
35871da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
35881da177e4SLinus Torvalds 
35891da177e4SLinus Torvalds 	if (!sdbg_host)
35901da177e4SLinus Torvalds 		return;
35911da177e4SLinus Torvalds 
35921da177e4SLinus Torvalds         device_unregister(&sdbg_host->dev);
35931da177e4SLinus Torvalds         --scsi_debug_add_host;
35941da177e4SLinus Torvalds }
35951da177e4SLinus Torvalds 
3596639db475SFUJITA Tomonori static
3597f281233dSJeff Garzik int scsi_debug_queuecommand_lck(struct scsi_cmnd *SCpnt, done_funct_t done)
3598639db475SFUJITA Tomonori {
3599639db475SFUJITA Tomonori 	unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
3600639db475SFUJITA Tomonori 	int len, k;
3601639db475SFUJITA Tomonori 	unsigned int num;
3602639db475SFUJITA Tomonori 	unsigned long long lba;
3603395cef03SMartin K. Petersen 	u32 ei_lba;
3604639db475SFUJITA Tomonori 	int errsts = 0;
3605639db475SFUJITA Tomonori 	int target = SCpnt->device->id;
3606639db475SFUJITA Tomonori 	struct sdebug_dev_info *devip = NULL;
3607639db475SFUJITA Tomonori 	int inj_recovered = 0;
3608639db475SFUJITA Tomonori 	int inj_transport = 0;
3609c6a44287SMartin K. Petersen 	int inj_dif = 0;
3610c6a44287SMartin K. Petersen 	int inj_dix = 0;
3611639db475SFUJITA Tomonori 	int delay_override = 0;
361244d92694SMartin K. Petersen 	int unmap = 0;
3613639db475SFUJITA Tomonori 
3614639db475SFUJITA Tomonori 	scsi_set_resid(SCpnt, 0);
3615639db475SFUJITA Tomonori 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
3616639db475SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: cmd ");
3617639db475SFUJITA Tomonori 		for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
3618639db475SFUJITA Tomonori 			printk("%02x ", (int)cmd[k]);
3619639db475SFUJITA Tomonori 		printk("\n");
3620639db475SFUJITA Tomonori 	}
3621639db475SFUJITA Tomonori 
3622639db475SFUJITA Tomonori 	if (target == SCpnt->device->host->hostt->this_id) {
3623639db475SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: initiator's id used as "
3624639db475SFUJITA Tomonori 		       "target!\n");
3625639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
3626639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
3627639db475SFUJITA Tomonori 	}
3628639db475SFUJITA Tomonori 
3629639db475SFUJITA Tomonori 	if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
3630639db475SFUJITA Tomonori 	    (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
3631639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
3632639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
3633639db475SFUJITA Tomonori 	devip = devInfoReg(SCpnt->device);
3634639db475SFUJITA Tomonori 	if (NULL == devip)
3635639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
3636639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
3637639db475SFUJITA Tomonori 
3638639db475SFUJITA Tomonori 	if ((scsi_debug_every_nth != 0) &&
3639639db475SFUJITA Tomonori 	    (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
3640639db475SFUJITA Tomonori 		scsi_debug_cmnd_count = 0;
3641639db475SFUJITA Tomonori 		if (scsi_debug_every_nth < -1)
3642639db475SFUJITA Tomonori 			scsi_debug_every_nth = -1;
3643639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
3644639db475SFUJITA Tomonori 			return 0; /* ignore command causing timeout */
364518a4d0a2SMartin K. Petersen 		else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts &&
364618a4d0a2SMartin K. Petersen 			 scsi_medium_access_command(SCpnt))
364718a4d0a2SMartin K. Petersen 			return 0; /* time out reads and writes */
3648639db475SFUJITA Tomonori 		else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
3649639db475SFUJITA Tomonori 			inj_recovered = 1; /* to reads and writes below */
3650639db475SFUJITA Tomonori 		else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
3651639db475SFUJITA Tomonori 			inj_transport = 1; /* to reads and writes below */
3652c6a44287SMartin K. Petersen 		else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
3653c6a44287SMartin K. Petersen 			inj_dif = 1; /* to reads and writes below */
3654c6a44287SMartin K. Petersen 		else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
3655c6a44287SMartin K. Petersen 			inj_dix = 1; /* to reads and writes below */
3656639db475SFUJITA Tomonori 	}
3657639db475SFUJITA Tomonori 
3658639db475SFUJITA Tomonori 	if (devip->wlun) {
3659639db475SFUJITA Tomonori 		switch (*cmd) {
3660639db475SFUJITA Tomonori 		case INQUIRY:
3661639db475SFUJITA Tomonori 		case REQUEST_SENSE:
3662639db475SFUJITA Tomonori 		case TEST_UNIT_READY:
3663639db475SFUJITA Tomonori 		case REPORT_LUNS:
3664639db475SFUJITA Tomonori 			break;  /* only allowable wlun commands */
3665639db475SFUJITA Tomonori 		default:
3666639db475SFUJITA Tomonori 			if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3667639db475SFUJITA Tomonori 				printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
3668639db475SFUJITA Tomonori 				       "not supported for wlun\n", *cmd);
3669639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3670639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
3671639db475SFUJITA Tomonori 			errsts = check_condition_result;
3672639db475SFUJITA Tomonori 			return schedule_resp(SCpnt, devip, done, errsts,
3673639db475SFUJITA Tomonori 					     0);
3674639db475SFUJITA Tomonori 		}
3675639db475SFUJITA Tomonori 	}
3676639db475SFUJITA Tomonori 
3677639db475SFUJITA Tomonori 	switch (*cmd) {
3678639db475SFUJITA Tomonori 	case INQUIRY:     /* mandatory, ignore unit attention */
3679639db475SFUJITA Tomonori 		delay_override = 1;
3680639db475SFUJITA Tomonori 		errsts = resp_inquiry(SCpnt, target, devip);
3681639db475SFUJITA Tomonori 		break;
3682639db475SFUJITA Tomonori 	case REQUEST_SENSE:	/* mandatory, ignore unit attention */
3683639db475SFUJITA Tomonori 		delay_override = 1;
3684639db475SFUJITA Tomonori 		errsts = resp_requests(SCpnt, devip);
3685639db475SFUJITA Tomonori 		break;
3686639db475SFUJITA Tomonori 	case REZERO_UNIT:	/* actually this is REWIND for SSC */
3687639db475SFUJITA Tomonori 	case START_STOP:
3688639db475SFUJITA Tomonori 		errsts = resp_start_stop(SCpnt, devip);
3689639db475SFUJITA Tomonori 		break;
3690639db475SFUJITA Tomonori 	case ALLOW_MEDIUM_REMOVAL:
3691639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3692639db475SFUJITA Tomonori 		if (errsts)
3693639db475SFUJITA Tomonori 			break;
3694639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3695639db475SFUJITA Tomonori 			printk(KERN_INFO "scsi_debug: Medium removal %s\n",
3696639db475SFUJITA Tomonori 			       cmd[4] ? "inhibited" : "enabled");
3697639db475SFUJITA Tomonori 		break;
3698639db475SFUJITA Tomonori 	case SEND_DIAGNOSTIC:     /* mandatory */
3699639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3700639db475SFUJITA Tomonori 		break;
3701639db475SFUJITA Tomonori 	case TEST_UNIT_READY:     /* mandatory */
3702639db475SFUJITA Tomonori 		delay_override = 1;
3703639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3704639db475SFUJITA Tomonori 		break;
3705639db475SFUJITA Tomonori 	case RESERVE:
3706639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3707639db475SFUJITA Tomonori 		break;
3708639db475SFUJITA Tomonori 	case RESERVE_10:
3709639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3710639db475SFUJITA Tomonori 		break;
3711639db475SFUJITA Tomonori 	case RELEASE:
3712639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3713639db475SFUJITA Tomonori 		break;
3714639db475SFUJITA Tomonori 	case RELEASE_10:
3715639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3716639db475SFUJITA Tomonori 		break;
3717639db475SFUJITA Tomonori 	case READ_CAPACITY:
3718639db475SFUJITA Tomonori 		errsts = resp_readcap(SCpnt, devip);
3719639db475SFUJITA Tomonori 		break;
3720639db475SFUJITA Tomonori 	case SERVICE_ACTION_IN:
372144d92694SMartin K. Petersen 		if (cmd[1] == SAI_READ_CAPACITY_16)
372244d92694SMartin K. Petersen 			errsts = resp_readcap16(SCpnt, devip);
372344d92694SMartin K. Petersen 		else if (cmd[1] == SAI_GET_LBA_STATUS) {
372444d92694SMartin K. Petersen 
37255b94e232SMartin K. Petersen 			if (scsi_debug_lbp() == 0) {
372644d92694SMartin K. Petersen 				mk_sense_buffer(devip, ILLEGAL_REQUEST,
372744d92694SMartin K. Petersen 						INVALID_COMMAND_OPCODE, 0);
372844d92694SMartin K. Petersen 				errsts = check_condition_result;
372944d92694SMartin K. Petersen 			} else
373044d92694SMartin K. Petersen 				errsts = resp_get_lba_status(SCpnt, devip);
373144d92694SMartin K. Petersen 		} else {
3732639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3733639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
3734639db475SFUJITA Tomonori 			errsts = check_condition_result;
3735639db475SFUJITA Tomonori 		}
3736639db475SFUJITA Tomonori 		break;
3737639db475SFUJITA Tomonori 	case MAINTENANCE_IN:
3738639db475SFUJITA Tomonori 		if (MI_REPORT_TARGET_PGS != cmd[1]) {
3739639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3740639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
3741639db475SFUJITA Tomonori 			errsts = check_condition_result;
3742639db475SFUJITA Tomonori 			break;
3743639db475SFUJITA Tomonori 		}
3744639db475SFUJITA Tomonori 		errsts = resp_report_tgtpgs(SCpnt, devip);
3745639db475SFUJITA Tomonori 		break;
3746639db475SFUJITA Tomonori 	case READ_16:
3747639db475SFUJITA Tomonori 	case READ_12:
3748639db475SFUJITA Tomonori 	case READ_10:
3749395cef03SMartin K. Petersen 		/* READ{10,12,16} and DIF Type 2 are natural enemies */
3750395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3751395cef03SMartin K. Petersen 		    cmd[1] & 0xe0) {
3752395cef03SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3753395cef03SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
3754395cef03SMartin K. Petersen 			errsts = check_condition_result;
3755395cef03SMartin K. Petersen 			break;
3756395cef03SMartin K. Petersen 		}
3757395cef03SMartin K. Petersen 
3758395cef03SMartin K. Petersen 		if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3759395cef03SMartin K. Petersen 		     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3760395cef03SMartin K. Petersen 		    (cmd[1] & 0xe0) == 0)
3761395cef03SMartin K. Petersen 			printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3762395cef03SMartin K. Petersen 
3763395cef03SMartin K. Petersen 		/* fall through */
3764639db475SFUJITA Tomonori 	case READ_6:
3765395cef03SMartin K. Petersen read:
3766639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3767639db475SFUJITA Tomonori 		if (errsts)
3768639db475SFUJITA Tomonori 			break;
3769639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
3770639db475SFUJITA Tomonori 			break;
3771395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3772395cef03SMartin K. Petersen 		errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
3773639db475SFUJITA Tomonori 		if (inj_recovered && (0 == errsts)) {
3774639db475SFUJITA Tomonori 			mk_sense_buffer(devip, RECOVERED_ERROR,
3775639db475SFUJITA Tomonori 					THRESHOLD_EXCEEDED, 0);
3776639db475SFUJITA Tomonori 			errsts = check_condition_result;
3777639db475SFUJITA Tomonori 		} else if (inj_transport && (0 == errsts)) {
3778639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ABORTED_COMMAND,
3779639db475SFUJITA Tomonori 					TRANSPORT_PROBLEM, ACK_NAK_TO);
3780639db475SFUJITA Tomonori 			errsts = check_condition_result;
3781c6a44287SMartin K. Petersen 		} else if (inj_dif && (0 == errsts)) {
3782c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3783c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3784c6a44287SMartin K. Petersen 		} else if (inj_dix && (0 == errsts)) {
3785c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3786c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3787639db475SFUJITA Tomonori 		}
3788639db475SFUJITA Tomonori 		break;
3789639db475SFUJITA Tomonori 	case REPORT_LUNS:	/* mandatory, ignore unit attention */
3790639db475SFUJITA Tomonori 		delay_override = 1;
3791639db475SFUJITA Tomonori 		errsts = resp_report_luns(SCpnt, devip);
3792639db475SFUJITA Tomonori 		break;
3793639db475SFUJITA Tomonori 	case VERIFY:		/* 10 byte SBC-2 command */
3794639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3795639db475SFUJITA Tomonori 		break;
3796639db475SFUJITA Tomonori 	case WRITE_16:
3797639db475SFUJITA Tomonori 	case WRITE_12:
3798639db475SFUJITA Tomonori 	case WRITE_10:
3799395cef03SMartin K. Petersen 		/* WRITE{10,12,16} and DIF Type 2 are natural enemies */
3800395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3801395cef03SMartin K. Petersen 		    cmd[1] & 0xe0) {
3802395cef03SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3803395cef03SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
3804395cef03SMartin K. Petersen 			errsts = check_condition_result;
3805395cef03SMartin K. Petersen 			break;
3806395cef03SMartin K. Petersen 		}
3807395cef03SMartin K. Petersen 
3808395cef03SMartin K. Petersen 		if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3809395cef03SMartin K. Petersen 		     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3810395cef03SMartin K. Petersen 		    (cmd[1] & 0xe0) == 0)
3811395cef03SMartin K. Petersen 			printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3812395cef03SMartin K. Petersen 
3813395cef03SMartin K. Petersen 		/* fall through */
3814639db475SFUJITA Tomonori 	case WRITE_6:
3815395cef03SMartin K. Petersen write:
3816639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3817639db475SFUJITA Tomonori 		if (errsts)
3818639db475SFUJITA Tomonori 			break;
3819639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
3820639db475SFUJITA Tomonori 			break;
3821395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3822395cef03SMartin K. Petersen 		errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
3823639db475SFUJITA Tomonori 		if (inj_recovered && (0 == errsts)) {
3824639db475SFUJITA Tomonori 			mk_sense_buffer(devip, RECOVERED_ERROR,
3825639db475SFUJITA Tomonori 					THRESHOLD_EXCEEDED, 0);
3826639db475SFUJITA Tomonori 			errsts = check_condition_result;
3827c6a44287SMartin K. Petersen 		} else if (inj_dif && (0 == errsts)) {
3828c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3829c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3830c6a44287SMartin K. Petersen 		} else if (inj_dix && (0 == errsts)) {
3831c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3832c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3833639db475SFUJITA Tomonori 		}
3834639db475SFUJITA Tomonori 		break;
383544d92694SMartin K. Petersen 	case WRITE_SAME_16:
38365b94e232SMartin K. Petersen 	case WRITE_SAME:
38376014759cSMartin K. Petersen 		if (cmd[1] & 0x8) {
38385b94e232SMartin K. Petersen 			if ((*cmd == WRITE_SAME_16 && scsi_debug_lbpws == 0) ||
38395b94e232SMartin K. Petersen 			    (*cmd == WRITE_SAME && scsi_debug_lbpws10 == 0)) {
38406014759cSMartin K. Petersen 				mk_sense_buffer(devip, ILLEGAL_REQUEST,
38416014759cSMartin K. Petersen 						INVALID_FIELD_IN_CDB, 0);
38426014759cSMartin K. Petersen 				errsts = check_condition_result;
38436014759cSMartin K. Petersen 			} else
384444d92694SMartin K. Petersen 				unmap = 1;
38456014759cSMartin K. Petersen 		}
38466014759cSMartin K. Petersen 		if (errsts)
38476014759cSMartin K. Petersen 			break;
384844d92694SMartin K. Petersen 		errsts = check_readiness(SCpnt, 0, devip);
384944d92694SMartin K. Petersen 		if (errsts)
385044d92694SMartin K. Petersen 			break;
385144d92694SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
385244d92694SMartin K. Petersen 		errsts = resp_write_same(SCpnt, lba, num, devip, ei_lba, unmap);
385344d92694SMartin K. Petersen 		break;
385444d92694SMartin K. Petersen 	case UNMAP:
385544d92694SMartin K. Petersen 		errsts = check_readiness(SCpnt, 0, devip);
385644d92694SMartin K. Petersen 		if (errsts)
385744d92694SMartin K. Petersen 			break;
385844d92694SMartin K. Petersen 
38595b94e232SMartin K. Petersen 		if (scsi_debug_unmap_max_desc == 0 || scsi_debug_lbpu == 0) {
386044d92694SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
386144d92694SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
386244d92694SMartin K. Petersen 			errsts = check_condition_result;
386344d92694SMartin K. Petersen 		} else
386444d92694SMartin K. Petersen 			errsts = resp_unmap(SCpnt, devip);
386544d92694SMartin K. Petersen 		break;
3866639db475SFUJITA Tomonori 	case MODE_SENSE:
3867639db475SFUJITA Tomonori 	case MODE_SENSE_10:
3868639db475SFUJITA Tomonori 		errsts = resp_mode_sense(SCpnt, target, devip);
3869639db475SFUJITA Tomonori 		break;
3870639db475SFUJITA Tomonori 	case MODE_SELECT:
3871639db475SFUJITA Tomonori 		errsts = resp_mode_select(SCpnt, 1, devip);
3872639db475SFUJITA Tomonori 		break;
3873639db475SFUJITA Tomonori 	case MODE_SELECT_10:
3874639db475SFUJITA Tomonori 		errsts = resp_mode_select(SCpnt, 0, devip);
3875639db475SFUJITA Tomonori 		break;
3876639db475SFUJITA Tomonori 	case LOG_SENSE:
3877639db475SFUJITA Tomonori 		errsts = resp_log_sense(SCpnt, devip);
3878639db475SFUJITA Tomonori 		break;
3879639db475SFUJITA Tomonori 	case SYNCHRONIZE_CACHE:
3880639db475SFUJITA Tomonori 		delay_override = 1;
3881639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3882639db475SFUJITA Tomonori 		break;
3883639db475SFUJITA Tomonori 	case WRITE_BUFFER:
3884639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3885639db475SFUJITA Tomonori 		break;
3886639db475SFUJITA Tomonori 	case XDWRITEREAD_10:
3887639db475SFUJITA Tomonori 		if (!scsi_bidi_cmnd(SCpnt)) {
3888639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3889639db475SFUJITA Tomonori 					INVALID_FIELD_IN_CDB, 0);
3890639db475SFUJITA Tomonori 			errsts = check_condition_result;
3891639db475SFUJITA Tomonori 			break;
3892639db475SFUJITA Tomonori 		}
3893639db475SFUJITA Tomonori 
3894639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3895639db475SFUJITA Tomonori 		if (errsts)
3896639db475SFUJITA Tomonori 			break;
3897639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
3898639db475SFUJITA Tomonori 			break;
3899395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3900395cef03SMartin K. Petersen 		errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
3901639db475SFUJITA Tomonori 		if (errsts)
3902639db475SFUJITA Tomonori 			break;
3903395cef03SMartin K. Petersen 		errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
3904639db475SFUJITA Tomonori 		if (errsts)
3905639db475SFUJITA Tomonori 			break;
3906639db475SFUJITA Tomonori 		errsts = resp_xdwriteread(SCpnt, lba, num, devip);
3907639db475SFUJITA Tomonori 		break;
3908395cef03SMartin K. Petersen 	case VARIABLE_LENGTH_CMD:
3909395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
3910395cef03SMartin K. Petersen 
3911395cef03SMartin K. Petersen 			if ((cmd[10] & 0xe0) == 0)
3912395cef03SMartin K. Petersen 				printk(KERN_ERR
3913395cef03SMartin K. Petersen 				       "Unprotected RD/WR to DIF device\n");
3914395cef03SMartin K. Petersen 
3915395cef03SMartin K. Petersen 			if (cmd[9] == READ_32) {
3916395cef03SMartin K. Petersen 				BUG_ON(SCpnt->cmd_len < 32);
3917395cef03SMartin K. Petersen 				goto read;
3918395cef03SMartin K. Petersen 			}
3919395cef03SMartin K. Petersen 
3920395cef03SMartin K. Petersen 			if (cmd[9] == WRITE_32) {
3921395cef03SMartin K. Petersen 				BUG_ON(SCpnt->cmd_len < 32);
3922395cef03SMartin K. Petersen 				goto write;
3923395cef03SMartin K. Petersen 			}
3924395cef03SMartin K. Petersen 		}
3925395cef03SMartin K. Petersen 
3926395cef03SMartin K. Petersen 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
3927395cef03SMartin K. Petersen 				INVALID_FIELD_IN_CDB, 0);
3928395cef03SMartin K. Petersen 		errsts = check_condition_result;
3929395cef03SMartin K. Petersen 		break;
3930395cef03SMartin K. Petersen 
3931639db475SFUJITA Tomonori 	default:
3932639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3933639db475SFUJITA Tomonori 			printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
3934639db475SFUJITA Tomonori 			       "supported\n", *cmd);
3935639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3936639db475SFUJITA Tomonori 		if (errsts)
3937639db475SFUJITA Tomonori 			break;	/* Unit attention takes precedence */
3938639db475SFUJITA Tomonori 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
3939639db475SFUJITA Tomonori 		errsts = check_condition_result;
3940639db475SFUJITA Tomonori 		break;
3941639db475SFUJITA Tomonori 	}
3942639db475SFUJITA Tomonori 	return schedule_resp(SCpnt, devip, done, errsts,
3943639db475SFUJITA Tomonori 			     (delay_override ? 0 : scsi_debug_delay));
3944639db475SFUJITA Tomonori }
3945639db475SFUJITA Tomonori 
3946f281233dSJeff Garzik static DEF_SCSI_QCMD(scsi_debug_queuecommand)
3947f281233dSJeff Garzik 
39489e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
3949c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
3950c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
39519e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
39529e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
39539e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
39549e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
39559e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
39569e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
39579e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
39589e603ca0SFUJITA Tomonori 	.queuecommand =		scsi_debug_queuecommand,
39599e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
39609e603ca0SFUJITA Tomonori 	.eh_bus_reset_handler = scsi_debug_bus_reset,
39619e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
39629e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
39639e603ca0SFUJITA Tomonori 	.bios_param =		scsi_debug_biosparam,
39649e603ca0SFUJITA Tomonori 	.can_queue =		SCSI_DEBUG_CANQUEUE,
39659e603ca0SFUJITA Tomonori 	.this_id =		7,
39669e603ca0SFUJITA Tomonori 	.sg_tablesize =		256,
39679e603ca0SFUJITA Tomonori 	.cmd_per_lun =		16,
39689e603ca0SFUJITA Tomonori 	.max_sectors =		0xffff,
39699e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
39709e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
39719e603ca0SFUJITA Tomonori };
39729e603ca0SFUJITA Tomonori 
39731da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev)
39741da177e4SLinus Torvalds {
39751da177e4SLinus Torvalds         int error = 0;
39761da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
39771da177e4SLinus Torvalds         struct Scsi_Host *hpnt;
3978c6a44287SMartin K. Petersen 	int host_prot;
39791da177e4SLinus Torvalds 
39801da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
39811da177e4SLinus Torvalds 
398278d4e5a0SDouglas Gilbert 	sdebug_driver_template.can_queue = scsi_debug_max_queue;
39831da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
39841da177e4SLinus Torvalds 	if (NULL == hpnt) {
3985cadbd4a5SHarvey Harrison 		printk(KERN_ERR "%s: scsi_register failed\n", __func__);
39861da177e4SLinus Torvalds 		error = -ENODEV;
39871da177e4SLinus Torvalds 		return error;
39881da177e4SLinus Torvalds 	}
39891da177e4SLinus Torvalds 
39901da177e4SLinus Torvalds         sdbg_host->shost = hpnt;
39911da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
39921da177e4SLinus Torvalds 	if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
39931da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts + 1;
39941da177e4SLinus Torvalds 	else
39951da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts;
3996c65b1445SDouglas Gilbert 	hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;	/* = scsi_debug_max_luns; */
39971da177e4SLinus Torvalds 
3998c6a44287SMartin K. Petersen 	host_prot = 0;
3999c6a44287SMartin K. Petersen 
4000c6a44287SMartin K. Petersen 	switch (scsi_debug_dif) {
4001c6a44287SMartin K. Petersen 
4002c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
4003c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE1_PROTECTION;
4004c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
4005c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE1_PROTECTION;
4006c6a44287SMartin K. Petersen 		break;
4007c6a44287SMartin K. Petersen 
4008c6a44287SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
4009c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE2_PROTECTION;
4010c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
4011c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE2_PROTECTION;
4012c6a44287SMartin K. Petersen 		break;
4013c6a44287SMartin K. Petersen 
4014c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
4015c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE3_PROTECTION;
4016c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
4017c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE3_PROTECTION;
4018c6a44287SMartin K. Petersen 		break;
4019c6a44287SMartin K. Petersen 
4020c6a44287SMartin K. Petersen 	default:
4021c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
4022c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE0_PROTECTION;
4023c6a44287SMartin K. Petersen 		break;
4024c6a44287SMartin K. Petersen 	}
4025c6a44287SMartin K. Petersen 
4026c6a44287SMartin K. Petersen 	scsi_host_set_prot(hpnt, host_prot);
4027c6a44287SMartin K. Petersen 
4028c6a44287SMartin K. Petersen 	printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
4029c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
4030c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
4031c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
4032c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
4033c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
4034c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
4035c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
4036c6a44287SMartin K. Petersen 
4037c6a44287SMartin K. Petersen 	if (scsi_debug_guard == 1)
4038c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
4039c6a44287SMartin K. Petersen 	else
4040c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
4041c6a44287SMartin K. Petersen 
40421da177e4SLinus Torvalds         error = scsi_add_host(hpnt, &sdbg_host->dev);
40431da177e4SLinus Torvalds         if (error) {
4044cadbd4a5SHarvey Harrison                 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
40451da177e4SLinus Torvalds                 error = -ENODEV;
40461da177e4SLinus Torvalds 		scsi_host_put(hpnt);
40471da177e4SLinus Torvalds         } else
40481da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
40491da177e4SLinus Torvalds 
40501da177e4SLinus Torvalds 
40511da177e4SLinus Torvalds         return error;
40521da177e4SLinus Torvalds }
40531da177e4SLinus Torvalds 
40541da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev)
40551da177e4SLinus Torvalds {
40561da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
40578b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
40581da177e4SLinus Torvalds 
40591da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
40601da177e4SLinus Torvalds 
40611da177e4SLinus Torvalds 	if (!sdbg_host) {
40621da177e4SLinus Torvalds 		printk(KERN_ERR "%s: Unable to locate host info\n",
4063cadbd4a5SHarvey Harrison 		       __func__);
40641da177e4SLinus Torvalds 		return -ENODEV;
40651da177e4SLinus Torvalds 	}
40661da177e4SLinus Torvalds 
40671da177e4SLinus Torvalds         scsi_remove_host(sdbg_host->shost);
40681da177e4SLinus Torvalds 
40698b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
40708b40228fSFUJITA Tomonori 				 dev_list) {
40711da177e4SLinus Torvalds                 list_del(&sdbg_devinfo->dev_list);
40721da177e4SLinus Torvalds                 kfree(sdbg_devinfo);
40731da177e4SLinus Torvalds         }
40741da177e4SLinus Torvalds 
40751da177e4SLinus Torvalds         scsi_host_put(sdbg_host->shost);
40761da177e4SLinus Torvalds         return 0;
40771da177e4SLinus Torvalds }
40781da177e4SLinus Torvalds 
40798dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
40808dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
40811da177e4SLinus Torvalds {
40828dea0d02SFUJITA Tomonori 	return 1;
40838dea0d02SFUJITA Tomonori }
40841da177e4SLinus Torvalds 
40858dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
40868dea0d02SFUJITA Tomonori 	.name = "pseudo",
40878dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
40888dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
40898dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
40908dea0d02SFUJITA Tomonori };
4091