xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision de13e965)
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
1045b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
1055b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1061da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1071da177e4SLinus Torvalds #define DEF_OPTS   0
108e308b3d1SMartin K. Petersen #define DEF_OPT_BLKS 64
1095b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
1105b94e232SMartin K. Petersen #define DEF_PTYPE   0
1115b94e232SMartin K. Petersen #define DEF_SCSI_LEVEL   5    /* INQUIRY, byte2 [5->SPC-3] */
1125b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1135b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1145b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1156014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1166014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1175b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1185b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1195b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */
1221da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE   1
1231da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR   2
1241da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT   4
1251da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR   8
1266f3cbf55SDouglas Gilbert #define SCSI_DEBUG_OPT_TRANSPORT_ERR   16
127c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIF_ERR   32
128c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIX_ERR   64
1291da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
1301da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1311da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1321da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1336f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1346f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1351da177e4SLinus Torvalds  *
1361da177e4SLinus Torvalds  * When "every_nth" < 0 then after "- every_nth" commands:
1371da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1381da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1391da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1406f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1416f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1421da177e4SLinus Torvalds  * This will continue until some other action occurs (e.g. the user
1431da177e4SLinus Torvalds  * writing a new value (other than -1 or 1) to every_nth via sysfs).
1441da177e4SLinus Torvalds  */
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
1471da177e4SLinus Torvalds  * sector on read commands: */
1481da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
14932f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
1501da177e4SLinus Torvalds 
1511da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
1521da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
1531da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
154c65b1445SDouglas Gilbert #define SAM2_WLUN_REPORT_LUNS 0xc101
1551da177e4SLinus Torvalds 
15678d4e5a0SDouglas Gilbert /* Can queue up to this number of commands. Typically commands that
15778d4e5a0SDouglas Gilbert  * that have a non-zero delay are queued. */
15878d4e5a0SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE  255
15978d4e5a0SDouglas Gilbert 
1601da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST;
1615b94e232SMartin K. Petersen static int scsi_debug_ato = DEF_ATO;
1621da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY;
1631da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
1645b94e232SMartin K. Petersen static int scsi_debug_dif = DEF_DIF;
1655b94e232SMartin K. Petersen static int scsi_debug_dix = DEF_DIX;
1665b94e232SMartin K. Petersen static int scsi_debug_dsense = DEF_D_SENSE;
1671da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH;
1685b94e232SMartin K. Petersen static int scsi_debug_fake_rw = DEF_FAKE_RW;
1695b94e232SMartin K. Petersen static int scsi_debug_guard = DEF_GUARD;
1705b94e232SMartin K. Petersen static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
1711da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS;
17278d4e5a0SDouglas Gilbert static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE;
173c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
1745b94e232SMartin K. Petersen static int scsi_debug_no_uld = 0;
1755b94e232SMartin K. Petersen static int scsi_debug_num_parts = DEF_NUM_PARTS;
1765b94e232SMartin K. Petersen static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
177e308b3d1SMartin K. Petersen static int scsi_debug_opt_blks = DEF_OPT_BLKS;
1785b94e232SMartin K. Petersen static int scsi_debug_opts = DEF_OPTS;
1795b94e232SMartin K. Petersen static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
1805b94e232SMartin K. Petersen static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
1815b94e232SMartin K. Petersen static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
1825b94e232SMartin K. Petersen static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
1835b94e232SMartin K. Petersen static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
1845b94e232SMartin K. Petersen static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
1855b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpu = DEF_LBPU;
1865b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws = DEF_LBPWS;
1875b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10;
1886014759cSMartin K. Petersen static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
1895b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
1905b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
1915b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
1925b94e232SMartin K. Petersen static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH;
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds static int scsi_debug_cmnd_count = 0;
1951da177e4SLinus Torvalds 
1961da177e4SLinus Torvalds #define DEV_READONLY(TGT)      (0)
1971da177e4SLinus Torvalds #define DEV_REMOVEABLE(TGT)    (0)
1981da177e4SLinus Torvalds 
199c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
2001da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
2031da177e4SLinus Torvalds    may still need them */
2041da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
2051da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
2061da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
2071da177e4SLinus Torvalds 
2081da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds #define SDEBUG_SENSE_LEN 32
2111da177e4SLinus Torvalds 
212395cef03SMartin K. Petersen #define SCSI_DEBUG_MAX_CMD_LEN 32
2139e603ca0SFUJITA Tomonori 
2145b94e232SMartin K. Petersen static unsigned int scsi_debug_lbp(void)
2155b94e232SMartin K. Petersen {
2165b94e232SMartin K. Petersen 	return scsi_debug_lbpu | scsi_debug_lbpws | scsi_debug_lbpws10;
2175b94e232SMartin K. Petersen }
2185b94e232SMartin K. Petersen 
2191da177e4SLinus Torvalds struct sdebug_dev_info {
2201da177e4SLinus Torvalds 	struct list_head dev_list;
2211da177e4SLinus Torvalds 	unsigned char sense_buff[SDEBUG_SENSE_LEN];	/* weak nexus */
2221da177e4SLinus Torvalds 	unsigned int channel;
2231da177e4SLinus Torvalds 	unsigned int target;
2241da177e4SLinus Torvalds 	unsigned int lun;
2251da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
226c65b1445SDouglas Gilbert 	unsigned int wlun;
2271da177e4SLinus Torvalds 	char reset;
228c65b1445SDouglas Gilbert 	char stopped;
2291da177e4SLinus Torvalds 	char used;
2301da177e4SLinus Torvalds };
2311da177e4SLinus Torvalds 
2321da177e4SLinus Torvalds struct sdebug_host_info {
2331da177e4SLinus Torvalds 	struct list_head host_list;
2341da177e4SLinus Torvalds 	struct Scsi_Host *shost;
2351da177e4SLinus Torvalds 	struct device dev;
2361da177e4SLinus Torvalds 	struct list_head dev_info_list;
2371da177e4SLinus Torvalds };
2381da177e4SLinus Torvalds 
2391da177e4SLinus Torvalds #define to_sdebug_host(d)	\
2401da177e4SLinus Torvalds 	container_of(d, struct sdebug_host_info, dev)
2411da177e4SLinus Torvalds 
2421da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
2431da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
2441da177e4SLinus Torvalds 
2451da177e4SLinus Torvalds typedef void (* done_funct_t) (struct scsi_cmnd *);
2461da177e4SLinus Torvalds 
2471da177e4SLinus Torvalds struct sdebug_queued_cmd {
2481da177e4SLinus Torvalds 	int in_use;
2491da177e4SLinus Torvalds 	struct timer_list cmnd_timer;
2501da177e4SLinus Torvalds 	done_funct_t done_funct;
2511da177e4SLinus Torvalds 	struct scsi_cmnd * a_cmnd;
2521da177e4SLinus Torvalds 	int scsi_result;
2531da177e4SLinus Torvalds };
2541da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds static unsigned char * fake_storep;	/* ramdisk storage */
257c6a44287SMartin K. Petersen static unsigned char *dif_storep;	/* protection info */
25844d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
2591da177e4SLinus Torvalds 
26044d92694SMartin K. Petersen static unsigned long map_size;
2611da177e4SLinus Torvalds static int num_aborts = 0;
2621da177e4SLinus Torvalds static int num_dev_resets = 0;
2631da177e4SLinus Torvalds static int num_bus_resets = 0;
2641da177e4SLinus Torvalds static int num_host_resets = 0;
265c6a44287SMartin K. Petersen static int dix_writes;
266c6a44287SMartin K. Petersen static int dix_reads;
267c6a44287SMartin K. Petersen static int dif_errors;
2681da177e4SLinus Torvalds 
2691da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock);
2701da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds static char sdebug_proc_name[] = "scsi_debug";
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
2751da177e4SLinus Torvalds 
276c6a44287SMartin K. Petersen static inline sector_t dif_offset(sector_t sector)
277c6a44287SMartin K. Petersen {
278c6a44287SMartin K. Petersen 	return sector << 3;
279c6a44287SMartin K. Petersen }
280c6a44287SMartin K. Petersen 
2811da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
2821da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
2831da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
2841da177e4SLinus Torvalds };
2851da177e4SLinus Torvalds 
2861da177e4SLinus Torvalds static const int check_condition_result =
2871da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
2881da177e4SLinus Torvalds 
289c6a44287SMartin K. Petersen static const int illegal_condition_result =
290c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
291c6a44287SMartin K. Petersen 
292c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
293c65b1445SDouglas Gilbert 				    0, 0, 0x2, 0x4b};
294c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
295c65b1445SDouglas Gilbert 			           0, 0, 0x0, 0x0};
296c65b1445SDouglas Gilbert 
2971da177e4SLinus Torvalds static int sdebug_add_adapter(void);
2981da177e4SLinus Torvalds static void sdebug_remove_adapter(void);
2991da177e4SLinus Torvalds 
3008dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
3018dea0d02SFUJITA Tomonori {
3028dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
3038dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
3048dea0d02SFUJITA Tomonori 
3058dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
3068dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3078dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
3088dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
3098dea0d02SFUJITA Tomonori 		    (scsi_debug_num_tgts > hpnt->this_id))
3108dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts + 1;
3118dea0d02SFUJITA Tomonori 		else
3128dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts;
3138dea0d02SFUJITA Tomonori 		/* scsi_debug_max_luns; */
3148dea0d02SFUJITA Tomonori 		hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
3158dea0d02SFUJITA Tomonori 	}
3168dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
3178dea0d02SFUJITA Tomonori }
3188dea0d02SFUJITA Tomonori 
3198dea0d02SFUJITA Tomonori static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
3208dea0d02SFUJITA Tomonori 			    int asc, int asq)
3218dea0d02SFUJITA Tomonori {
3228dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
3238dea0d02SFUJITA Tomonori 
3248dea0d02SFUJITA Tomonori 	sbuff = devip->sense_buff;
3258dea0d02SFUJITA Tomonori 	memset(sbuff, 0, SDEBUG_SENSE_LEN);
3268dea0d02SFUJITA Tomonori 
3278dea0d02SFUJITA Tomonori 	scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
3288dea0d02SFUJITA Tomonori 
3298dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3308dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug:    [sense_key,asc,ascq]: "
3318dea0d02SFUJITA Tomonori 		      "[0x%x,0x%x,0x%x]\n", key, asc, asq);
3328dea0d02SFUJITA Tomonori }
3331da177e4SLinus Torvalds 
3343de9f944SFUJITA Tomonori static void get_data_transfer_info(unsigned char *cmd,
335395cef03SMartin K. Petersen 				   unsigned long long *lba, unsigned int *num,
336395cef03SMartin K. Petersen 				   u32 *ei_lba)
3373de9f944SFUJITA Tomonori {
338395cef03SMartin K. Petersen 	*ei_lba = 0;
339395cef03SMartin K. Petersen 
3403de9f944SFUJITA Tomonori 	switch (*cmd) {
341395cef03SMartin K. Petersen 	case VARIABLE_LENGTH_CMD:
342395cef03SMartin K. Petersen 		*lba = (u64)cmd[19] | (u64)cmd[18] << 8 |
343395cef03SMartin K. Petersen 			(u64)cmd[17] << 16 | (u64)cmd[16] << 24 |
344395cef03SMartin K. Petersen 			(u64)cmd[15] << 32 | (u64)cmd[14] << 40 |
345395cef03SMartin K. Petersen 			(u64)cmd[13] << 48 | (u64)cmd[12] << 56;
346395cef03SMartin K. Petersen 
347395cef03SMartin K. Petersen 		*ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 |
348395cef03SMartin K. Petersen 			(u32)cmd[21] << 16 | (u32)cmd[20] << 24;
349395cef03SMartin K. Petersen 
350395cef03SMartin K. Petersen 		*num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 |
351395cef03SMartin K. Petersen 			(u32)cmd[28] << 24;
352395cef03SMartin K. Petersen 		break;
353395cef03SMartin K. Petersen 
35444d92694SMartin K. Petersen 	case WRITE_SAME_16:
3553de9f944SFUJITA Tomonori 	case WRITE_16:
3563de9f944SFUJITA Tomonori 	case READ_16:
357d5cdc989SFUJITA Tomonori 		*lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
358d5cdc989SFUJITA Tomonori 			(u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
359d5cdc989SFUJITA Tomonori 			(u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
360d5cdc989SFUJITA Tomonori 			(u64)cmd[3] << 48 | (u64)cmd[2] << 56;
361d5cdc989SFUJITA Tomonori 
362d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
363d5cdc989SFUJITA Tomonori 			(u32)cmd[10] << 24;
3643de9f944SFUJITA Tomonori 		break;
3653de9f944SFUJITA Tomonori 	case WRITE_12:
3663de9f944SFUJITA Tomonori 	case READ_12:
367d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
368d5cdc989SFUJITA Tomonori 			(u32)cmd[2] << 24;
369d5cdc989SFUJITA Tomonori 
370d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
371d5cdc989SFUJITA Tomonori 			(u32)cmd[6] << 24;
3723de9f944SFUJITA Tomonori 		break;
37344d92694SMartin K. Petersen 	case WRITE_SAME:
3743de9f944SFUJITA Tomonori 	case WRITE_10:
3753de9f944SFUJITA Tomonori 	case READ_10:
376c639d14eSFUJITA Tomonori 	case XDWRITEREAD_10:
377d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[5] | (u32)cmd[4] << 8 |	(u32)cmd[3] << 16 |
378d5cdc989SFUJITA Tomonori 			(u32)cmd[2] << 24;
379d5cdc989SFUJITA Tomonori 
380d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[8] | (u32)cmd[7] << 8;
3813de9f944SFUJITA Tomonori 		break;
3823de9f944SFUJITA Tomonori 	case WRITE_6:
3833de9f944SFUJITA Tomonori 	case READ_6:
384d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
385d5cdc989SFUJITA Tomonori 			(u32)(cmd[1] & 0x1f) << 16;
3863de9f944SFUJITA Tomonori 		*num = (0 == cmd[4]) ? 256 : cmd[4];
3873de9f944SFUJITA Tomonori 		break;
3883de9f944SFUJITA Tomonori 	default:
3893de9f944SFUJITA Tomonori 		break;
3903de9f944SFUJITA Tomonori 	}
3913de9f944SFUJITA Tomonori }
3921da177e4SLinus Torvalds 
3931da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
3941da177e4SLinus Torvalds {
3951da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
3961da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
3971da177e4SLinus Torvalds 	}
3981da177e4SLinus Torvalds 	return -EINVAL;
3991da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
4001da177e4SLinus Torvalds }
4011da177e4SLinus Torvalds 
402c65b1445SDouglas Gilbert static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
403c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
4041da177e4SLinus Torvalds {
4051da177e4SLinus Torvalds 	if (devip->reset) {
4061da177e4SLinus Torvalds 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
4071da177e4SLinus Torvalds 			printk(KERN_INFO "scsi_debug: Reporting Unit "
4081da177e4SLinus Torvalds 			       "attention: power on reset\n");
4091da177e4SLinus Torvalds 		devip->reset = 0;
4101da177e4SLinus Torvalds 		mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
4111da177e4SLinus Torvalds 		return check_condition_result;
4121da177e4SLinus Torvalds 	}
413c65b1445SDouglas Gilbert 	if ((0 == reset_only) && devip->stopped) {
414c65b1445SDouglas Gilbert 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
415c65b1445SDouglas Gilbert 			printk(KERN_INFO "scsi_debug: Reporting Not "
416c65b1445SDouglas Gilbert 			       "ready: initializing command required\n");
417c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
418c65b1445SDouglas Gilbert 				0x2);
419c65b1445SDouglas Gilbert 		return check_condition_result;
420c65b1445SDouglas Gilbert 	}
4211da177e4SLinus Torvalds 	return 0;
4221da177e4SLinus Torvalds }
4231da177e4SLinus Torvalds 
4241da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
4251da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
4261da177e4SLinus Torvalds 				int arr_len)
4271da177e4SLinus Torvalds {
42821a61829SFUJITA Tomonori 	int act_len;
429072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
4301da177e4SLinus Torvalds 
431072d0bb3SFUJITA Tomonori 	if (!sdb->length)
4321da177e4SLinus Torvalds 		return 0;
433072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
4341da177e4SLinus Torvalds 		return (DID_ERROR << 16);
43521a61829SFUJITA Tomonori 
43621a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
43721a61829SFUJITA Tomonori 				      arr, arr_len);
438072d0bb3SFUJITA Tomonori 	if (sdb->resid)
439072d0bb3SFUJITA Tomonori 		sdb->resid -= act_len;
440c65b1445SDouglas Gilbert 	else
44121a61829SFUJITA Tomonori 		sdb->resid = scsi_bufflen(scp) - act_len;
44221a61829SFUJITA Tomonori 
4431da177e4SLinus Torvalds 	return 0;
4441da177e4SLinus Torvalds }
4451da177e4SLinus Torvalds 
4461da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */
4471da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
44821a61829SFUJITA Tomonori 			       int arr_len)
4491da177e4SLinus Torvalds {
45021a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
4511da177e4SLinus Torvalds 		return 0;
452072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
4531da177e4SLinus Torvalds 		return -1;
45421a61829SFUJITA Tomonori 
45521a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
4561da177e4SLinus Torvalds }
4571da177e4SLinus Torvalds 
4581da177e4SLinus Torvalds 
4591da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux   ";
4601da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug      ";
4611da177e4SLinus Torvalds static const char * inq_product_rev = "0004";
4621da177e4SLinus Torvalds 
4635a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
4645a09e398SHannes Reinecke 			   int target_dev_id, int dev_id_num,
4655a09e398SHannes Reinecke 			   const char * dev_id_str,
466c65b1445SDouglas Gilbert 			   int dev_id_str_len)
4671da177e4SLinus Torvalds {
468c65b1445SDouglas Gilbert 	int num, port_a;
469c65b1445SDouglas Gilbert 	char b[32];
4701da177e4SLinus Torvalds 
471c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
4721da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
4731da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
4741da177e4SLinus Torvalds 	arr[1] = 0x1;
4751da177e4SLinus Torvalds 	arr[2] = 0x0;
4761da177e4SLinus Torvalds 	memcpy(&arr[4], inq_vendor_id, 8);
4771da177e4SLinus Torvalds 	memcpy(&arr[12], inq_product_id, 16);
4781da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
4791da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
4801da177e4SLinus Torvalds 	arr[3] = num;
4811da177e4SLinus Torvalds 	num += 4;
482c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
483c65b1445SDouglas Gilbert 		/* NAA-5, Logical unit identifier (binary) */
484c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* binary (not necessarily sas) */
485c65b1445SDouglas Gilbert 		arr[num++] = 0x3;	/* PIV=0, lu, naa */
486c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
487c65b1445SDouglas Gilbert 		arr[num++] = 0x8;
488c65b1445SDouglas Gilbert 		arr[num++] = 0x53;  /* naa-5 ieee company id=0x333333 (fake) */
489c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
490c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
491c65b1445SDouglas Gilbert 		arr[num++] = 0x30;
492c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 24);
493c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 16) & 0xff;
494c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 8) & 0xff;
495c65b1445SDouglas Gilbert 		arr[num++] = dev_id_num & 0xff;
496c65b1445SDouglas Gilbert 		/* Target relative port number */
497c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
498c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
499c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
500c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
501c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
502c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
503c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
504c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
505c65b1445SDouglas Gilbert 	}
506c65b1445SDouglas Gilbert 	/* NAA-5, Target port identifier */
507c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
508c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
509c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
510c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
511c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
512c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
513c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
514c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
515c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
516c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
517c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
518c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
5195a09e398SHannes Reinecke 	/* NAA-5, Target port group identifier */
5205a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
5215a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
5225a09e398SHannes Reinecke 	arr[num++] = 0x0;
5235a09e398SHannes Reinecke 	arr[num++] = 0x4;
5245a09e398SHannes Reinecke 	arr[num++] = 0;
5255a09e398SHannes Reinecke 	arr[num++] = 0;
5265a09e398SHannes Reinecke 	arr[num++] = (port_group_id >> 8) & 0xff;
5275a09e398SHannes Reinecke 	arr[num++] = port_group_id & 0xff;
528c65b1445SDouglas Gilbert 	/* NAA-5, Target device identifier */
529c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
530c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
531c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
532c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
533c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
534c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
535c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
536c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
537c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 24);
538c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 16) & 0xff;
539c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 8) & 0xff;
540c65b1445SDouglas Gilbert 	arr[num++] = target_dev_id & 0xff;
541c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
542c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
543c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
544c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
545c65b1445SDouglas Gilbert 	arr[num++] = 24;
546c65b1445SDouglas Gilbert 	memcpy(arr + num, "naa.52222220", 12);
547c65b1445SDouglas Gilbert 	num += 12;
548c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
549c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
550c65b1445SDouglas Gilbert 	num += 8;
551c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
552c65b1445SDouglas Gilbert 	num += 4;
553c65b1445SDouglas Gilbert 	return num;
554c65b1445SDouglas Gilbert }
555c65b1445SDouglas Gilbert 
556c65b1445SDouglas Gilbert 
557c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
558c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
559c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
560c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
561c65b1445SDouglas Gilbert };
562c65b1445SDouglas Gilbert 
563c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr)
564c65b1445SDouglas Gilbert {
565c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
566c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
567c65b1445SDouglas Gilbert }
568c65b1445SDouglas Gilbert 
569c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr)
570c65b1445SDouglas Gilbert {
571c65b1445SDouglas Gilbert 	int num = 0;
572c65b1445SDouglas Gilbert 	const char * na1 = "https://www.kernel.org/config";
573c65b1445SDouglas Gilbert 	const char * na2 = "http://www.kernel.org/log";
574c65b1445SDouglas Gilbert 	int plen, olen;
575c65b1445SDouglas Gilbert 
576c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
577c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
578c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
579c65b1445SDouglas Gilbert 	olen = strlen(na1);
580c65b1445SDouglas Gilbert 	plen = olen + 1;
581c65b1445SDouglas Gilbert 	if (plen % 4)
582c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
583c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
584c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
585c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
586c65b1445SDouglas Gilbert 	num += plen;
587c65b1445SDouglas Gilbert 
588c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
589c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
590c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
591c65b1445SDouglas Gilbert 	olen = strlen(na2);
592c65b1445SDouglas Gilbert 	plen = olen + 1;
593c65b1445SDouglas Gilbert 	if (plen % 4)
594c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
595c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
596c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
597c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
598c65b1445SDouglas Gilbert 	num += plen;
599c65b1445SDouglas Gilbert 
600c65b1445SDouglas Gilbert 	return num;
601c65b1445SDouglas Gilbert }
602c65b1445SDouglas Gilbert 
603c65b1445SDouglas Gilbert /* SCSI ports VPD page */
604c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
605c65b1445SDouglas Gilbert {
606c65b1445SDouglas Gilbert 	int num = 0;
607c65b1445SDouglas Gilbert 	int port_a, port_b;
608c65b1445SDouglas Gilbert 
609c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
610c65b1445SDouglas Gilbert 	port_b = port_a + 1;
611c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
612c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
613c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
614c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
615c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
616c65b1445SDouglas Gilbert 	num += 6;
617c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
618c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
619c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
620c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
621c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
622c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
623c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
624c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
625c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
626c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
627c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
628c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
629c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
630c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
631c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
632c65b1445SDouglas Gilbert 
633c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
634c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
635c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
636c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
637c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
638c65b1445SDouglas Gilbert 	num += 6;
639c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
640c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
641c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
642c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
643c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
644c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
645c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
646c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
647c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
648c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
649c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
650c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 24);
651c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 16) & 0xff;
652c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 8) & 0xff;
653c65b1445SDouglas Gilbert 	arr[num++] = port_b & 0xff;
654c65b1445SDouglas Gilbert 
655c65b1445SDouglas Gilbert 	return num;
656c65b1445SDouglas Gilbert }
657c65b1445SDouglas Gilbert 
658c65b1445SDouglas Gilbert 
659c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
660c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
661c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
662c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
663c65b1445SDouglas Gilbert '1','2','3','4',
664c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
665c65b1445SDouglas Gilbert 0xec,0,0,0,
666c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
667c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
668c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
669c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
670c65b1445SDouglas Gilbert 0x53,0x41,
671c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
672c65b1445SDouglas Gilbert 0x20,0x20,
673c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
674c65b1445SDouglas Gilbert 0x10,0x80,
675c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
676c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
677c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
678c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
679c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
680c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
681c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
682c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
683c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
684c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
685c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
686c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
687c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
688c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0,
697c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
698c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
699c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
700c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
701c65b1445SDouglas Gilbert };
702c65b1445SDouglas Gilbert 
703c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr)
704c65b1445SDouglas Gilbert {
705c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
706c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
707c65b1445SDouglas Gilbert }
708c65b1445SDouglas Gilbert 
709c65b1445SDouglas Gilbert 
7101e49f785SDouglas Gilbert /* Block limits VPD page (SBC-3) */
711c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
7121e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
7131e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7141e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7151e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
716c65b1445SDouglas Gilbert };
717c65b1445SDouglas Gilbert 
718c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr)
719c65b1445SDouglas Gilbert {
720ea61fca5SMartin K. Petersen 	unsigned int gran;
721ea61fca5SMartin K. Petersen 
722c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
723e308b3d1SMartin K. Petersen 
724e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
725ea61fca5SMartin K. Petersen 	gran = 1 << scsi_debug_physblk_exp;
726ea61fca5SMartin K. Petersen 	arr[2] = (gran >> 8) & 0xff;
727ea61fca5SMartin K. Petersen 	arr[3] = gran & 0xff;
728e308b3d1SMartin K. Petersen 
729e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
730c65b1445SDouglas Gilbert 	if (sdebug_store_sectors > 0x400) {
731c65b1445SDouglas Gilbert 		arr[4] = (sdebug_store_sectors >> 24) & 0xff;
732c65b1445SDouglas Gilbert 		arr[5] = (sdebug_store_sectors >> 16) & 0xff;
733c65b1445SDouglas Gilbert 		arr[6] = (sdebug_store_sectors >> 8) & 0xff;
734c65b1445SDouglas Gilbert 		arr[7] = sdebug_store_sectors & 0xff;
735c65b1445SDouglas Gilbert 	}
73644d92694SMartin K. Petersen 
737e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
738e308b3d1SMartin K. Petersen 	put_unaligned_be32(scsi_debug_opt_blks, &arr[8]);
739e308b3d1SMartin K. Petersen 
7405b94e232SMartin K. Petersen 	if (scsi_debug_lbpu) {
741e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
7426014759cSMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]);
743e308b3d1SMartin K. Petersen 
744e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
74544d92694SMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
74644d92694SMartin K. Petersen 	}
74744d92694SMartin K. Petersen 
748e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
74944d92694SMartin K. Petersen 	if (scsi_debug_unmap_alignment) {
75044d92694SMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
75144d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
75244d92694SMartin K. Petersen 	}
75344d92694SMartin K. Petersen 
754e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
75544d92694SMartin K. Petersen 	put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
7566014759cSMartin K. Petersen 
7575b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
7585b94e232SMartin K. Petersen 	put_unaligned_be64(scsi_debug_write_same_length, &arr[32]);
7595b94e232SMartin K. Petersen 
7605b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
76144d92694SMartin K. Petersen 
762c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
7631da177e4SLinus Torvalds }
7641da177e4SLinus Torvalds 
7651e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
766eac6e8e4SMatthew Wilcox static int inquiry_evpd_b1(unsigned char *arr)
767eac6e8e4SMatthew Wilcox {
768eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
769eac6e8e4SMatthew Wilcox 	arr[0] = 0;
7701e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
7711e49f785SDouglas Gilbert 	arr[2] = 0;
7721e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
773eac6e8e4SMatthew Wilcox 
774eac6e8e4SMatthew Wilcox 	return 0x3c;
775eac6e8e4SMatthew Wilcox }
7761da177e4SLinus Torvalds 
7776014759cSMartin K. Petersen /* Thin provisioning VPD page (SBC-3) */
7786014759cSMartin K. Petersen static int inquiry_evpd_b2(unsigned char *arr)
7796014759cSMartin K. Petersen {
7806014759cSMartin K. Petersen 	memset(arr, 0, 0x8);
7816014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
7826014759cSMartin K. Petersen 
7835b94e232SMartin K. Petersen 	if (scsi_debug_lbpu)
7846014759cSMartin K. Petersen 		arr[1] = 1 << 7;
7856014759cSMartin K. Petersen 
7865b94e232SMartin K. Petersen 	if (scsi_debug_lbpws)
7876014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
7886014759cSMartin K. Petersen 
7895b94e232SMartin K. Petersen 	if (scsi_debug_lbpws10)
7905b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
7915b94e232SMartin K. Petersen 
7926014759cSMartin K. Petersen 	return 0x8;
7936014759cSMartin K. Petersen }
7946014759cSMartin K. Petersen 
7951da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
796c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
7971da177e4SLinus Torvalds 
7981da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd * scp, int target,
7991da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
8001da177e4SLinus Torvalds {
8011da177e4SLinus Torvalds 	unsigned char pq_pdt;
8025a09e398SHannes Reinecke 	unsigned char * arr;
8031da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
8045a09e398SHannes Reinecke 	int alloc_len, n, ret;
8051da177e4SLinus Torvalds 
8061da177e4SLinus Torvalds 	alloc_len = (cmd[3] << 8) + cmd[4];
8076f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
8086f3cbf55SDouglas Gilbert 	if (! arr)
8096f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
810c65b1445SDouglas Gilbert 	if (devip->wlun)
811c65b1445SDouglas Gilbert 		pq_pdt = 0x1e;	/* present, wlun */
812c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (0 == devip->lun))
813c65b1445SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, no device type */
814c65b1445SDouglas Gilbert 	else
8151da177e4SLinus Torvalds 		pq_pdt = (scsi_debug_ptype & 0x1f);
8161da177e4SLinus Torvalds 	arr[0] = pq_pdt;
8171da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
8181da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
8191da177e4SLinus Torvalds 			       	0);
8205a09e398SHannes Reinecke 		kfree(arr);
8211da177e4SLinus Torvalds 		return check_condition_result;
8221da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
8235a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
824c65b1445SDouglas Gilbert 		char lu_id_str[6];
825c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
8261da177e4SLinus Torvalds 
8275a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
8285a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
82923183910SDouglas Gilbert 		if (0 == scsi_debug_vpd_use_hostno)
83023183910SDouglas Gilbert 			host_no = 0;
831c65b1445SDouglas Gilbert 		lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
832c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
833c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
834c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
835c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
8361da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
837c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
838c65b1445SDouglas Gilbert 			n = 4;
839c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
840c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
841c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
842c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
843c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
844c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
845c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
846c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
847c65b1445SDouglas Gilbert 			arr[n++] = 0x89;  /* ATA information */
848c65b1445SDouglas Gilbert 			arr[n++] = 0xb0;  /* Block limits (SBC) */
849eac6e8e4SMatthew Wilcox 			arr[n++] = 0xb1;  /* Block characteristics (SBC) */
8505b94e232SMartin K. Petersen 			if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
8515b94e232SMartin K. Petersen 				arr[n++] = 0xb2;
852c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
8531da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
854c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
8551da177e4SLinus Torvalds 			arr[3] = len;
856c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
8571da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
858c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
8595a09e398SHannes Reinecke 			arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
8605a09e398SHannes Reinecke 						 target_dev_id, lu_id_num,
8615a09e398SHannes Reinecke 						 lu_id_str, len);
862c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
863c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
864c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_84(&arr[4]);
865c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
866c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
867c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_85(&arr[4]);
868c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
869c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
870c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
871c6a44287SMartin K. Petersen 			if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
872c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
873c6a44287SMartin K. Petersen 			else if (scsi_debug_dif)
874c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
875c6a44287SMartin K. Petersen 			else
876c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
877c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
878c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
879c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
880c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
881c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
882c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
883c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
884c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
885c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
886c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
887c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
888c65b1445SDouglas Gilbert 		} else if (0x89 == cmd[2]) { /* ATA information */
889c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
890c65b1445SDouglas Gilbert 			n = inquiry_evpd_89(&arr[4]);
891c65b1445SDouglas Gilbert 			arr[2] = (n >> 8);
892c65b1445SDouglas Gilbert 			arr[3] = (n & 0xff);
893c65b1445SDouglas Gilbert 		} else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
894c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
895c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_b0(&arr[4]);
896eac6e8e4SMatthew Wilcox 		} else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
897eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
898eac6e8e4SMatthew Wilcox 			arr[3] = inquiry_evpd_b1(&arr[4]);
8995b94e232SMartin K. Petersen 		} else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
9006014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
9016014759cSMartin K. Petersen 			arr[3] = inquiry_evpd_b2(&arr[4]);
9021da177e4SLinus Torvalds 		} else {
9031da177e4SLinus Torvalds 			/* Illegal request, invalid field in cdb */
9041da177e4SLinus Torvalds 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
9051da177e4SLinus Torvalds 					INVALID_FIELD_IN_CDB, 0);
9065a09e398SHannes Reinecke 			kfree(arr);
9071da177e4SLinus Torvalds 			return check_condition_result;
9081da177e4SLinus Torvalds 		}
909c65b1445SDouglas Gilbert 		len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
9105a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
911c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
9125a09e398SHannes Reinecke 		kfree(arr);
9135a09e398SHannes Reinecke 		return ret;
9141da177e4SLinus Torvalds 	}
9151da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
9161da177e4SLinus Torvalds 	arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0;	/* Removable disk */
9171da177e4SLinus Torvalds 	arr[2] = scsi_debug_scsi_level;
9181da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
9191da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
920c6a44287SMartin K. Petersen 	arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
9215a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno)
9225a09e398SHannes Reinecke 		arr[5] = 0x10; /* claim: implicit TGPS */
923c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
9241da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
925c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
9261da177e4SLinus Torvalds 	memcpy(&arr[8], inq_vendor_id, 8);
9271da177e4SLinus Torvalds 	memcpy(&arr[16], inq_product_id, 16);
9281da177e4SLinus Torvalds 	memcpy(&arr[32], inq_product_rev, 4);
9291da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
930c65b1445SDouglas Gilbert 	arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
931c65b1445SDouglas Gilbert 	arr[60] = 0x3; arr[61] = 0x14;  /* SPC-3 ANSI */
932c65b1445SDouglas Gilbert 	n = 62;
9331da177e4SLinus Torvalds 	if (scsi_debug_ptype == 0) {
934c65b1445SDouglas Gilbert 		arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
9351da177e4SLinus Torvalds 	} else if (scsi_debug_ptype == 1) {
936c65b1445SDouglas Gilbert 		arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
9371da177e4SLinus Torvalds 	}
938c65b1445SDouglas Gilbert 	arr[n++] = 0xc; arr[n++] = 0xf;  /* SAS-1.1 rev 10 */
9395a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
9401da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
9415a09e398SHannes Reinecke 	kfree(arr);
9425a09e398SHannes Reinecke 	return ret;
9431da177e4SLinus Torvalds }
9441da177e4SLinus Torvalds 
9451da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp,
9461da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip)
9471da177e4SLinus Torvalds {
9481da177e4SLinus Torvalds 	unsigned char * sbuff;
9491da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
9501da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_SENSE_LEN];
951c65b1445SDouglas Gilbert 	int want_dsense;
9521da177e4SLinus Torvalds 	int len = 18;
9531da177e4SLinus Torvalds 
954c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
9551da177e4SLinus Torvalds 	if (devip->reset == 1)
956c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
957c65b1445SDouglas Gilbert 	want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
9581da177e4SLinus Torvalds 	sbuff = devip->sense_buff;
959c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
960c65b1445SDouglas Gilbert 		if (want_dsense) {
961c65b1445SDouglas Gilbert 			arr[0] = 0x72;
962c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
963c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
964c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
965c65b1445SDouglas Gilbert 		} else {
966c65b1445SDouglas Gilbert 			arr[0] = 0x70;
967c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
968c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
969c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
970c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
971c65b1445SDouglas Gilbert 		}
972c65b1445SDouglas Gilbert 	} else {
973c65b1445SDouglas Gilbert 		memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
9741da177e4SLinus Torvalds 		if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
9751da177e4SLinus Torvalds 			/* DESC bit set and sense_buff in fixed format */
976c65b1445SDouglas Gilbert 			memset(arr, 0, sizeof(arr));
9771da177e4SLinus Torvalds 			arr[0] = 0x72;
9781da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
9791da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
9801da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
9811da177e4SLinus Torvalds 			len = 8;
982c65b1445SDouglas Gilbert 		}
983c65b1445SDouglas Gilbert 	}
984c65b1445SDouglas Gilbert 	mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
9851da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
9861da177e4SLinus Torvalds }
9871da177e4SLinus Torvalds 
988c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp,
989c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
990c65b1445SDouglas Gilbert {
991c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
992c65b1445SDouglas Gilbert 	int power_cond, errsts, start;
993c65b1445SDouglas Gilbert 
994c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
995c65b1445SDouglas Gilbert 		return errsts;
996c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
997c65b1445SDouglas Gilbert 	if (power_cond) {
998c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
999c65b1445SDouglas Gilbert 			       	0);
1000c65b1445SDouglas Gilbert 		return check_condition_result;
1001c65b1445SDouglas Gilbert 	}
1002c65b1445SDouglas Gilbert 	start = cmd[4] & 1;
1003c65b1445SDouglas Gilbert 	if (start == devip->stopped)
1004c65b1445SDouglas Gilbert 		devip->stopped = !start;
1005c65b1445SDouglas Gilbert 	return 0;
1006c65b1445SDouglas Gilbert }
1007c65b1445SDouglas Gilbert 
100828898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
100928898873SFUJITA Tomonori {
101028898873SFUJITA Tomonori 	if (scsi_debug_virtual_gb > 0)
10115447ed6cSDouglas Gilbert 		return (sector_t)scsi_debug_virtual_gb *
10125447ed6cSDouglas Gilbert 			(1073741824 / scsi_debug_sector_size);
101328898873SFUJITA Tomonori 	else
101428898873SFUJITA Tomonori 		return sdebug_store_sectors;
101528898873SFUJITA Tomonori }
101628898873SFUJITA Tomonori 
10171da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
10181da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp,
10191da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
10201da177e4SLinus Torvalds {
10211da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1022c65b1445SDouglas Gilbert 	unsigned int capac;
10231da177e4SLinus Torvalds 	int errsts;
10241da177e4SLinus Torvalds 
1025c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
10261da177e4SLinus Torvalds 		return errsts;
1027c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
102828898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
10291da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1030c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1031c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
10321da177e4SLinus Torvalds 		arr[0] = (capac >> 24);
10331da177e4SLinus Torvalds 		arr[1] = (capac >> 16) & 0xff;
10341da177e4SLinus Torvalds 		arr[2] = (capac >> 8) & 0xff;
10351da177e4SLinus Torvalds 		arr[3] = capac & 0xff;
1036c65b1445SDouglas Gilbert 	} else {
1037c65b1445SDouglas Gilbert 		arr[0] = 0xff;
1038c65b1445SDouglas Gilbert 		arr[1] = 0xff;
1039c65b1445SDouglas Gilbert 		arr[2] = 0xff;
1040c65b1445SDouglas Gilbert 		arr[3] = 0xff;
1041c65b1445SDouglas Gilbert 	}
1042597136abSMartin K. Petersen 	arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
1043597136abSMartin K. Petersen 	arr[7] = scsi_debug_sector_size & 0xff;
10441da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
10451da177e4SLinus Torvalds }
10461da177e4SLinus Torvalds 
1047c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1048c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp,
1049c65b1445SDouglas Gilbert 			  struct sdebug_dev_info * devip)
1050c65b1445SDouglas Gilbert {
1051c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1052c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1053c65b1445SDouglas Gilbert 	unsigned long long capac;
1054c65b1445SDouglas Gilbert 	int errsts, k, alloc_len;
1055c65b1445SDouglas Gilbert 
1056c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1057c65b1445SDouglas Gilbert 		return errsts;
1058c65b1445SDouglas Gilbert 	alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1059c65b1445SDouglas Gilbert 		     + cmd[13]);
1060c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
106128898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1062c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1063c65b1445SDouglas Gilbert 	capac = sdebug_capacity - 1;
1064c65b1445SDouglas Gilbert 	for (k = 0; k < 8; ++k, capac >>= 8)
1065c65b1445SDouglas Gilbert 		arr[7 - k] = capac & 0xff;
1066597136abSMartin K. Petersen 	arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
1067597136abSMartin K. Petersen 	arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
1068597136abSMartin K. Petersen 	arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
1069597136abSMartin K. Petersen 	arr[11] = scsi_debug_sector_size & 0xff;
1070ea61fca5SMartin K. Petersen 	arr[13] = scsi_debug_physblk_exp & 0xf;
1071ea61fca5SMartin K. Petersen 	arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
107244d92694SMartin K. Petersen 
10735b94e232SMartin K. Petersen 	if (scsi_debug_lbp())
10745b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
107544d92694SMartin K. Petersen 
1076ea61fca5SMartin K. Petersen 	arr[15] = scsi_debug_lowest_aligned & 0xff;
1077c6a44287SMartin K. Petersen 
1078c6a44287SMartin K. Petersen 	if (scsi_debug_dif) {
1079c6a44287SMartin K. Petersen 		arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
1080c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1081c6a44287SMartin K. Petersen 	}
1082c6a44287SMartin K. Petersen 
1083c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1084c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1085c65b1445SDouglas Gilbert }
1086c65b1445SDouglas Gilbert 
10875a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
10885a09e398SHannes Reinecke 
10895a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp,
10905a09e398SHannes Reinecke 			      struct sdebug_dev_info * devip)
10915a09e398SHannes Reinecke {
10925a09e398SHannes Reinecke 	unsigned char *cmd = (unsigned char *)scp->cmnd;
10935a09e398SHannes Reinecke 	unsigned char * arr;
10945a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
10955a09e398SHannes Reinecke 	int n, ret, alen, rlen;
10965a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
10975a09e398SHannes Reinecke 
10985a09e398SHannes Reinecke 	alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
10995a09e398SHannes Reinecke 		+ cmd[9]);
11005a09e398SHannes Reinecke 
11016f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
11026f3cbf55SDouglas Gilbert 	if (! arr)
11036f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
11045a09e398SHannes Reinecke 	/*
11055a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
11065a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
11075a09e398SHannes Reinecke 	 * So we create two port groups with one port each
11085a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
11095a09e398SHannes Reinecke 	 */
11105a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
11115a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
11125a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
11135a09e398SHannes Reinecke 	    (devip->channel & 0x7f);
11145a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
11155a09e398SHannes Reinecke 	    (devip->channel & 0x7f) + 0x80;
11165a09e398SHannes Reinecke 
11175a09e398SHannes Reinecke 	/*
11185a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
11195a09e398SHannes Reinecke 	 */
11205a09e398SHannes Reinecke 	n = 4;
11215a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno) {
11225a09e398SHannes Reinecke 	    arr[n++] = host_no % 3; /* Asymm access state */
11235a09e398SHannes Reinecke 	    arr[n++] = 0x0F; /* claim: all states are supported */
11245a09e398SHannes Reinecke 	} else {
11255a09e398SHannes Reinecke 	    arr[n++] = 0x0; /* Active/Optimized path */
11265a09e398SHannes Reinecke 	    arr[n++] = 0x01; /* claim: only support active/optimized paths */
11275a09e398SHannes Reinecke 	}
11285a09e398SHannes Reinecke 	arr[n++] = (port_group_a >> 8) & 0xff;
11295a09e398SHannes Reinecke 	arr[n++] = port_group_a & 0xff;
11305a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11315a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
11325a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
11335a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
11345a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11355a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11365a09e398SHannes Reinecke 	arr[n++] = (port_a >> 8) & 0xff;
11375a09e398SHannes Reinecke 	arr[n++] = port_a & 0xff;
11385a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
11395a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
11405a09e398SHannes Reinecke 	arr[n++] = (port_group_b >> 8) & 0xff;
11415a09e398SHannes Reinecke 	arr[n++] = port_group_b & 0xff;
11425a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11435a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
11445a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
11455a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
11465a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11475a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11485a09e398SHannes Reinecke 	arr[n++] = (port_b >> 8) & 0xff;
11495a09e398SHannes Reinecke 	arr[n++] = port_b & 0xff;
11505a09e398SHannes Reinecke 
11515a09e398SHannes Reinecke 	rlen = n - 4;
11525a09e398SHannes Reinecke 	arr[0] = (rlen >> 24) & 0xff;
11535a09e398SHannes Reinecke 	arr[1] = (rlen >> 16) & 0xff;
11545a09e398SHannes Reinecke 	arr[2] = (rlen >> 8) & 0xff;
11555a09e398SHannes Reinecke 	arr[3] = rlen & 0xff;
11565a09e398SHannes Reinecke 
11575a09e398SHannes Reinecke 	/*
11585a09e398SHannes Reinecke 	 * Return the smallest value of either
11595a09e398SHannes Reinecke 	 * - The allocated length
11605a09e398SHannes Reinecke 	 * - The constructed command length
11615a09e398SHannes Reinecke 	 * - The maximum array size
11625a09e398SHannes Reinecke 	 */
11635a09e398SHannes Reinecke 	rlen = min(alen,n);
11645a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
11655a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
11665a09e398SHannes Reinecke 	kfree(arr);
11675a09e398SHannes Reinecke 	return ret;
11685a09e398SHannes Reinecke }
11695a09e398SHannes Reinecke 
11701da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
11711da177e4SLinus Torvalds 
11721da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
11731da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
11741da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
11751da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
11761da177e4SLinus Torvalds 
11771da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
11781da177e4SLinus Torvalds 	if (1 == pcontrol)
11791da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
11801da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
11811da177e4SLinus Torvalds }
11821da177e4SLinus Torvalds 
11831da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
11841da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
11851da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
11861da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
11871da177e4SLinus Torvalds 
11881da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
11891da177e4SLinus Torvalds 	if (1 == pcontrol)
11901da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
11911da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
11921da177e4SLinus Torvalds }
11931da177e4SLinus Torvalds 
11941da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target)
11951da177e4SLinus Torvalds {       /* Format device page for mode_sense */
11961da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
11971da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
11981da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
11991da177e4SLinus Torvalds 
12001da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
12011da177e4SLinus Torvalds 	p[10] = (sdebug_sectors_per >> 8) & 0xff;
12021da177e4SLinus Torvalds 	p[11] = sdebug_sectors_per & 0xff;
1203597136abSMartin K. Petersen 	p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1204597136abSMartin K. Petersen 	p[13] = scsi_debug_sector_size & 0xff;
12051da177e4SLinus Torvalds 	if (DEV_REMOVEABLE(target))
12061da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
12071da177e4SLinus Torvalds 	if (1 == pcontrol)
12081da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
12091da177e4SLinus Torvalds 	return sizeof(format_pg);
12101da177e4SLinus Torvalds }
12111da177e4SLinus Torvalds 
12121da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
12131da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
12141da177e4SLinus Torvalds 	unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
12151da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
12161da177e4SLinus Torvalds 
12171da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
12181da177e4SLinus Torvalds 	if (1 == pcontrol)
12191da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(caching_pg) - 2);
12201da177e4SLinus Torvalds 	return sizeof(caching_pg);
12211da177e4SLinus Torvalds }
12221da177e4SLinus Torvalds 
12231da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
12241da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
1225c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1226c65b1445SDouglas Gilbert 				        0, 0, 0, 0};
1227c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
12281da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
12291da177e4SLinus Torvalds 
12301da177e4SLinus Torvalds 	if (scsi_debug_dsense)
12311da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
1232c65b1445SDouglas Gilbert 	else
1233c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
1234c6a44287SMartin K. Petersen 
1235c6a44287SMartin K. Petersen 	if (scsi_debug_ato)
1236c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1237c6a44287SMartin K. Petersen 
12381da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
12391da177e4SLinus Torvalds 	if (1 == pcontrol)
1240c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1241c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1242c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
12431da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
12441da177e4SLinus Torvalds }
12451da177e4SLinus Torvalds 
1246c65b1445SDouglas Gilbert 
12471da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
12481da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
1249c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
12501da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
1251c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1252c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
1253c65b1445SDouglas Gilbert 
12541da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
12551da177e4SLinus Torvalds 	if (1 == pcontrol)
1256c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1257c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1258c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
12591da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
12601da177e4SLinus Torvalds }
12611da177e4SLinus Torvalds 
1262c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1263c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
1264c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1265c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1266c65b1445SDouglas Gilbert 
1267c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1268c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1269c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1270c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
1271c65b1445SDouglas Gilbert }
1272c65b1445SDouglas Gilbert 
1273c65b1445SDouglas Gilbert 
1274c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1275c65b1445SDouglas Gilbert 			      int target_dev_id)
1276c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
1277c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1278c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1279c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1280c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1281c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
1282c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1283c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1284c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1285c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1286c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1287c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
1288c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1289c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1290c65b1445SDouglas Gilbert 		};
1291c65b1445SDouglas Gilbert 	int port_a, port_b;
1292c65b1445SDouglas Gilbert 
1293c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1294c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1295c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1296c65b1445SDouglas Gilbert 	p[20] = (port_a >> 24);
1297c65b1445SDouglas Gilbert 	p[21] = (port_a >> 16) & 0xff;
1298c65b1445SDouglas Gilbert 	p[22] = (port_a >> 8) & 0xff;
1299c65b1445SDouglas Gilbert 	p[23] = port_a & 0xff;
1300c65b1445SDouglas Gilbert 	p[48 + 20] = (port_b >> 24);
1301c65b1445SDouglas Gilbert 	p[48 + 21] = (port_b >> 16) & 0xff;
1302c65b1445SDouglas Gilbert 	p[48 + 22] = (port_b >> 8) & 0xff;
1303c65b1445SDouglas Gilbert 	p[48 + 23] = port_b & 0xff;
1304c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1305c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1306c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
1307c65b1445SDouglas Gilbert }
1308c65b1445SDouglas Gilbert 
1309c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1310c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
1311c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1312c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1313c65b1445SDouglas Gilbert 		};
1314c65b1445SDouglas Gilbert 
1315c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1316c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1317c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1318c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
1319c65b1445SDouglas Gilbert }
1320c65b1445SDouglas Gilbert 
13211da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
13221da177e4SLinus Torvalds 
13231da177e4SLinus Torvalds static int resp_mode_sense(struct scsi_cmnd * scp, int target,
13241da177e4SLinus Torvalds 			   struct sdebug_dev_info * devip)
13251da177e4SLinus Torvalds {
132623183910SDouglas Gilbert 	unsigned char dbd, llbaa;
132723183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
13281da177e4SLinus Torvalds 	unsigned char dev_spec;
132923183910SDouglas Gilbert 	int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
13301da177e4SLinus Torvalds 	unsigned char * ap;
13311da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
13321da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
13331da177e4SLinus Torvalds 
1334c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
13351da177e4SLinus Torvalds 		return errsts;
133623183910SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);
13371da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
13381da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
13391da177e4SLinus Torvalds 	subpcode = cmd[3];
13401da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
134123183910SDouglas Gilbert 	llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
134223183910SDouglas Gilbert 	if ((0 == scsi_debug_ptype) && (0 == dbd))
134323183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
134423183910SDouglas Gilbert 	else
134523183910SDouglas Gilbert 		bd_len = 0;
13461da177e4SLinus Torvalds 	alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
13471da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
13481da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
13491da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
13501da177e4SLinus Torvalds 			       	0);
13511da177e4SLinus Torvalds 		return check_condition_result;
13521da177e4SLinus Torvalds 	}
1353c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1354c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
135523183910SDouglas Gilbert 	/* set DPOFUA bit for disks */
135623183910SDouglas Gilbert 	if (0 == scsi_debug_ptype)
135723183910SDouglas Gilbert 		dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
135823183910SDouglas Gilbert 	else
135923183910SDouglas Gilbert 		dev_spec = 0x0;
13601da177e4SLinus Torvalds 	if (msense_6) {
13611da177e4SLinus Torvalds 		arr[2] = dev_spec;
136223183910SDouglas Gilbert 		arr[3] = bd_len;
13631da177e4SLinus Torvalds 		offset = 4;
13641da177e4SLinus Torvalds 	} else {
13651da177e4SLinus Torvalds 		arr[3] = dev_spec;
136623183910SDouglas Gilbert 		if (16 == bd_len)
136723183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
136823183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
13691da177e4SLinus Torvalds 		offset = 8;
13701da177e4SLinus Torvalds 	}
13711da177e4SLinus Torvalds 	ap = arr + offset;
137228898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
137328898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
137428898873SFUJITA Tomonori 
137523183910SDouglas Gilbert 	if (8 == bd_len) {
137623183910SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe) {
137723183910SDouglas Gilbert 			ap[0] = 0xff;
137823183910SDouglas Gilbert 			ap[1] = 0xff;
137923183910SDouglas Gilbert 			ap[2] = 0xff;
138023183910SDouglas Gilbert 			ap[3] = 0xff;
138123183910SDouglas Gilbert 		} else {
138223183910SDouglas Gilbert 			ap[0] = (sdebug_capacity >> 24) & 0xff;
138323183910SDouglas Gilbert 			ap[1] = (sdebug_capacity >> 16) & 0xff;
138423183910SDouglas Gilbert 			ap[2] = (sdebug_capacity >> 8) & 0xff;
138523183910SDouglas Gilbert 			ap[3] = sdebug_capacity & 0xff;
138623183910SDouglas Gilbert 		}
1387597136abSMartin K. Petersen 		ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1388597136abSMartin K. Petersen 		ap[7] = scsi_debug_sector_size & 0xff;
138923183910SDouglas Gilbert 		offset += bd_len;
139023183910SDouglas Gilbert 		ap = arr + offset;
139123183910SDouglas Gilbert 	} else if (16 == bd_len) {
139223183910SDouglas Gilbert 		unsigned long long capac = sdebug_capacity;
139323183910SDouglas Gilbert 
139423183910SDouglas Gilbert         	for (k = 0; k < 8; ++k, capac >>= 8)
139523183910SDouglas Gilbert                 	ap[7 - k] = capac & 0xff;
1396597136abSMartin K. Petersen 		ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1397597136abSMartin K. Petersen 		ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1398597136abSMartin K. Petersen 		ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1399597136abSMartin K. Petersen 		ap[15] = scsi_debug_sector_size & 0xff;
140023183910SDouglas Gilbert 		offset += bd_len;
140123183910SDouglas Gilbert 		ap = arr + offset;
140223183910SDouglas Gilbert 	}
14031da177e4SLinus Torvalds 
1404c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1405c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
14061da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
14071da177e4SLinus Torvalds 			       	0);
14081da177e4SLinus Torvalds 		return check_condition_result;
14091da177e4SLinus Torvalds 	}
14101da177e4SLinus Torvalds 	switch (pcode) {
14111da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
14121da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
14131da177e4SLinus Torvalds 		offset += len;
14141da177e4SLinus Torvalds 		break;
14151da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
14161da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
14171da177e4SLinus Torvalds 		offset += len;
14181da177e4SLinus Torvalds 		break;
14191da177e4SLinus Torvalds         case 0x3:       /* Format device page, direct access */
14201da177e4SLinus Torvalds                 len = resp_format_pg(ap, pcontrol, target);
14211da177e4SLinus Torvalds                 offset += len;
14221da177e4SLinus Torvalds                 break;
14231da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
14241da177e4SLinus Torvalds 		len = resp_caching_pg(ap, pcontrol, target);
14251da177e4SLinus Torvalds 		offset += len;
14261da177e4SLinus Torvalds 		break;
14271da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
14281da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
14291da177e4SLinus Torvalds 		offset += len;
14301da177e4SLinus Torvalds 		break;
1431c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
1432c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
1433c65b1445SDouglas Gilbert 		        mk_sense_buffer(devip, ILLEGAL_REQUEST,
1434c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1435c65b1445SDouglas Gilbert 			return check_condition_result;
1436c65b1445SDouglas Gilbert 	        }
1437c65b1445SDouglas Gilbert 		len = 0;
1438c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
1439c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1440c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
1441c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1442c65b1445SDouglas Gilbert 						  target_dev_id);
1443c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
1444c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
1445c65b1445SDouglas Gilbert 		offset += len;
1446c65b1445SDouglas Gilbert 		break;
14471da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
14481da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
14491da177e4SLinus Torvalds 		offset += len;
14501da177e4SLinus Torvalds 		break;
14511da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
1452c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
14531da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
14541da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
14551da177e4SLinus Torvalds 			len += resp_format_pg(ap + len, pcontrol, target);
14561da177e4SLinus Torvalds 			len += resp_caching_pg(ap + len, pcontrol, target);
14571da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1458c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1459c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
1460c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1461c65b1445SDouglas Gilbert 						  target, target_dev_id);
1462c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
1463c65b1445SDouglas Gilbert 			}
14641da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
1465c65b1445SDouglas Gilbert 		} else {
1466c65b1445SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
1467c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1468c65b1445SDouglas Gilbert 			return check_condition_result;
1469c65b1445SDouglas Gilbert                 }
14701da177e4SLinus Torvalds 		offset += len;
14711da177e4SLinus Torvalds 		break;
14721da177e4SLinus Torvalds 	default:
14731da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
14741da177e4SLinus Torvalds 			       	0);
14751da177e4SLinus Torvalds 		return check_condition_result;
14761da177e4SLinus Torvalds 	}
14771da177e4SLinus Torvalds 	if (msense_6)
14781da177e4SLinus Torvalds 		arr[0] = offset - 1;
14791da177e4SLinus Torvalds 	else {
14801da177e4SLinus Torvalds 		arr[0] = ((offset - 2) >> 8) & 0xff;
14811da177e4SLinus Torvalds 		arr[1] = (offset - 2) & 0xff;
14821da177e4SLinus Torvalds 	}
14831da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
14841da177e4SLinus Torvalds }
14851da177e4SLinus Torvalds 
1486c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
1487c65b1445SDouglas Gilbert 
1488c65b1445SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1489c65b1445SDouglas Gilbert 			    struct sdebug_dev_info * devip)
1490c65b1445SDouglas Gilbert {
1491c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1492c65b1445SDouglas Gilbert 	int param_len, res, errsts, mpage;
1493c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1494c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1495c65b1445SDouglas Gilbert 
1496c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1497c65b1445SDouglas Gilbert 		return errsts;
1498c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1499c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
1500c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
1501c65b1445SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1502c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1503c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1504c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
1505c65b1445SDouglas Gilbert 		return check_condition_result;
1506c65b1445SDouglas Gilbert 	}
1507c65b1445SDouglas Gilbert         res = fetch_to_dev_buffer(scp, arr, param_len);
1508c65b1445SDouglas Gilbert         if (-1 == res)
1509c65b1445SDouglas Gilbert                 return (DID_ERROR << 16);
1510c65b1445SDouglas Gilbert         else if ((res < param_len) &&
1511c65b1445SDouglas Gilbert                  (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1512c65b1445SDouglas Gilbert                 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1513c65b1445SDouglas Gilbert                        " IO sent=%d bytes\n", param_len, res);
1514c65b1445SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1515c65b1445SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
151623183910SDouglas Gilbert 	if (md_len > 2) {
1517c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1518c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_PARAM_LIST, 0);
1519c65b1445SDouglas Gilbert 		return check_condition_result;
1520c65b1445SDouglas Gilbert 	}
1521c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
1522c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
1523c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
1524c65b1445SDouglas Gilbert 	if (ps) {
1525c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1526c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_PARAM_LIST, 0);
1527c65b1445SDouglas Gilbert 		return check_condition_result;
1528c65b1445SDouglas Gilbert 	}
1529c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
1530c65b1445SDouglas Gilbert 	pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1531c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
1532c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
1533c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1534c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
1535c65b1445SDouglas Gilbert 		return check_condition_result;
1536c65b1445SDouglas Gilbert 	}
1537c65b1445SDouglas Gilbert 	switch (mpage) {
1538c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
1539c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
1540c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
1541c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
1542c65b1445SDouglas Gilbert 			scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1543c65b1445SDouglas Gilbert 			return 0;
1544c65b1445SDouglas Gilbert 		}
1545c65b1445SDouglas Gilbert 		break;
1546c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
1547c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
1548c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
1549c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
1550c65b1445SDouglas Gilbert 			return 0;
1551c65b1445SDouglas Gilbert 		}
1552c65b1445SDouglas Gilbert 		break;
1553c65b1445SDouglas Gilbert 	default:
1554c65b1445SDouglas Gilbert 		break;
1555c65b1445SDouglas Gilbert 	}
1556c65b1445SDouglas Gilbert 	mk_sense_buffer(devip, ILLEGAL_REQUEST,
1557c65b1445SDouglas Gilbert 			INVALID_FIELD_IN_PARAM_LIST, 0);
1558c65b1445SDouglas Gilbert 	return check_condition_result;
1559c65b1445SDouglas Gilbert }
1560c65b1445SDouglas Gilbert 
1561c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr)
1562c65b1445SDouglas Gilbert {
1563c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1564c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
1565c65b1445SDouglas Gilbert 		};
1566c65b1445SDouglas Gilbert 
1567c65b1445SDouglas Gilbert         memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1568c65b1445SDouglas Gilbert         return sizeof(temp_l_pg);
1569c65b1445SDouglas Gilbert }
1570c65b1445SDouglas Gilbert 
1571c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr)
1572c65b1445SDouglas Gilbert {
1573c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1574c65b1445SDouglas Gilbert 		};
1575c65b1445SDouglas Gilbert 
1576c65b1445SDouglas Gilbert         memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1577c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
1578c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
1579c65b1445SDouglas Gilbert 		arr[5] = 0xff;
1580c65b1445SDouglas Gilbert 	}
1581c65b1445SDouglas Gilbert         return sizeof(ie_l_pg);
1582c65b1445SDouglas Gilbert }
1583c65b1445SDouglas Gilbert 
1584c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
1585c65b1445SDouglas Gilbert 
1586c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp,
1587c65b1445SDouglas Gilbert                           struct sdebug_dev_info * devip)
1588c65b1445SDouglas Gilbert {
158923183910SDouglas Gilbert 	int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
1590c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1591c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1592c65b1445SDouglas Gilbert 
1593c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1594c65b1445SDouglas Gilbert 		return errsts;
1595c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1596c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
1597c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
1598c65b1445SDouglas Gilbert 	if (ppc || sp) {
1599c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1600c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
1601c65b1445SDouglas Gilbert 		return check_condition_result;
1602c65b1445SDouglas Gilbert 	}
1603c65b1445SDouglas Gilbert 	pcontrol = (cmd[2] & 0xc0) >> 6;
1604c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
160523183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
1606c65b1445SDouglas Gilbert 	alloc_len = (cmd[7] << 8) + cmd[8];
1607c65b1445SDouglas Gilbert 	arr[0] = pcode;
160823183910SDouglas Gilbert 	if (0 == subpcode) {
1609c65b1445SDouglas Gilbert 		switch (pcode) {
1610c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
1611c65b1445SDouglas Gilbert 			n = 4;
1612c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
1613c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
1614c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
1615c65b1445SDouglas Gilbert 			arr[3] = n - 4;
1616c65b1445SDouglas Gilbert 			break;
1617c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
1618c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
1619c65b1445SDouglas Gilbert 			break;
1620c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
1621c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
1622c65b1445SDouglas Gilbert 			break;
1623c65b1445SDouglas Gilbert 		default:
1624c65b1445SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
1625c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1626c65b1445SDouglas Gilbert 			return check_condition_result;
1627c65b1445SDouglas Gilbert 		}
162823183910SDouglas Gilbert 	} else if (0xff == subpcode) {
162923183910SDouglas Gilbert 		arr[0] |= 0x40;
163023183910SDouglas Gilbert 		arr[1] = subpcode;
163123183910SDouglas Gilbert 		switch (pcode) {
163223183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
163323183910SDouglas Gilbert 			n = 4;
163423183910SDouglas Gilbert 			arr[n++] = 0x0;
163523183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
163623183910SDouglas Gilbert 			arr[n++] = 0x0;
163723183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
163823183910SDouglas Gilbert 			arr[n++] = 0xd;
163923183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
164023183910SDouglas Gilbert 			arr[n++] = 0x2f;
164123183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
164223183910SDouglas Gilbert 			arr[3] = n - 4;
164323183910SDouglas Gilbert 			break;
164423183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
164523183910SDouglas Gilbert 			n = 4;
164623183910SDouglas Gilbert 			arr[n++] = 0xd;
164723183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
164823183910SDouglas Gilbert 			arr[3] = n - 4;
164923183910SDouglas Gilbert 			break;
165023183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
165123183910SDouglas Gilbert 			n = 4;
165223183910SDouglas Gilbert 			arr[n++] = 0x2f;
165323183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
165423183910SDouglas Gilbert 			arr[3] = n - 4;
165523183910SDouglas Gilbert 			break;
165623183910SDouglas Gilbert 		default:
165723183910SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
165823183910SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
165923183910SDouglas Gilbert 			return check_condition_result;
166023183910SDouglas Gilbert 		}
166123183910SDouglas Gilbert 	} else {
166223183910SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
166323183910SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
166423183910SDouglas Gilbert 		return check_condition_result;
166523183910SDouglas Gilbert 	}
1666c65b1445SDouglas Gilbert 	len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1667c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1668c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
1669c65b1445SDouglas Gilbert }
1670c65b1445SDouglas Gilbert 
167119789100SFUJITA Tomonori static int check_device_access_params(struct sdebug_dev_info *devi,
167219789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
16731da177e4SLinus Torvalds {
1674c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
167519789100SFUJITA Tomonori 		mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
16761da177e4SLinus Torvalds 		return check_condition_result;
16771da177e4SLinus Torvalds 	}
1678c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
1679c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
168019789100SFUJITA Tomonori 		mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
1681c65b1445SDouglas Gilbert 		return check_condition_result;
1682c65b1445SDouglas Gilbert 	}
168319789100SFUJITA Tomonori 	return 0;
168419789100SFUJITA Tomonori }
168519789100SFUJITA Tomonori 
168619789100SFUJITA Tomonori static int do_device_access(struct scsi_cmnd *scmd,
168719789100SFUJITA Tomonori 			    struct sdebug_dev_info *devi,
168819789100SFUJITA Tomonori 			    unsigned long long lba, unsigned int num, int write)
168919789100SFUJITA Tomonori {
169019789100SFUJITA Tomonori 	int ret;
1691a361cc00SDarrick J. Wong 	unsigned long long block, rest = 0;
169219789100SFUJITA Tomonori 	int (*func)(struct scsi_cmnd *, unsigned char *, int);
169319789100SFUJITA Tomonori 
169419789100SFUJITA Tomonori 	func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
169519789100SFUJITA Tomonori 
169619789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
169719789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
169819789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
169919789100SFUJITA Tomonori 
1700597136abSMartin K. Petersen 	ret = func(scmd, fake_storep + (block * scsi_debug_sector_size),
1701597136abSMartin K. Petersen 		   (num - rest) * scsi_debug_sector_size);
170219789100SFUJITA Tomonori 	if (!ret && rest)
1703597136abSMartin K. Petersen 		ret = func(scmd, fake_storep, rest * scsi_debug_sector_size);
170419789100SFUJITA Tomonori 
170519789100SFUJITA Tomonori 	return ret;
170619789100SFUJITA Tomonori }
170719789100SFUJITA Tomonori 
1708c6a44287SMartin K. Petersen static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
1709395cef03SMartin K. Petersen 			    unsigned int sectors, u32 ei_lba)
1710c6a44287SMartin K. Petersen {
1711c6a44287SMartin K. Petersen 	unsigned int i, resid;
1712c6a44287SMartin K. Petersen 	struct scatterlist *psgl;
1713c6a44287SMartin K. Petersen 	struct sd_dif_tuple *sdt;
1714c6a44287SMartin K. Petersen 	sector_t sector;
1715c6a44287SMartin K. Petersen 	sector_t tmp_sec = start_sec;
1716c6a44287SMartin K. Petersen 	void *paddr;
1717c6a44287SMartin K. Petersen 
1718c6a44287SMartin K. Petersen 	start_sec = do_div(tmp_sec, sdebug_store_sectors);
1719c6a44287SMartin K. Petersen 
1720c6a44287SMartin K. Petersen 	sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec));
1721c6a44287SMartin K. Petersen 
1722c6a44287SMartin K. Petersen 	for (i = 0 ; i < sectors ; i++) {
1723c6a44287SMartin K. Petersen 		u16 csum;
1724c6a44287SMartin K. Petersen 
1725c6a44287SMartin K. Petersen 		if (sdt[i].app_tag == 0xffff)
1726c6a44287SMartin K. Petersen 			continue;
1727c6a44287SMartin K. Petersen 
1728c6a44287SMartin K. Petersen 		sector = start_sec + i;
1729c6a44287SMartin K. Petersen 
1730c6a44287SMartin K. Petersen 		switch (scsi_debug_guard) {
1731c6a44287SMartin K. Petersen 		case 1:
1732c6a44287SMartin K. Petersen 			csum = ip_compute_csum(fake_storep +
1733c6a44287SMartin K. Petersen 					       sector * scsi_debug_sector_size,
1734c6a44287SMartin K. Petersen 					       scsi_debug_sector_size);
1735c6a44287SMartin K. Petersen 			break;
1736c6a44287SMartin K. Petersen 		case 0:
1737c6a44287SMartin K. Petersen 			csum = crc_t10dif(fake_storep +
1738c6a44287SMartin K. Petersen 					  sector * scsi_debug_sector_size,
1739c6a44287SMartin K. Petersen 					  scsi_debug_sector_size);
1740c6a44287SMartin K. Petersen 			csum = cpu_to_be16(csum);
1741c6a44287SMartin K. Petersen 			break;
1742c6a44287SMartin K. Petersen 		default:
1743c6a44287SMartin K. Petersen 			BUG();
1744c6a44287SMartin K. Petersen 		}
1745c6a44287SMartin K. Petersen 
1746c6a44287SMartin K. Petersen 		if (sdt[i].guard_tag != csum) {
1747c6a44287SMartin K. Petersen 			printk(KERN_ERR "%s: GUARD check failed on sector %lu" \
1748c6a44287SMartin K. Petersen 			       " rcvd 0x%04x, data 0x%04x\n", __func__,
1749c6a44287SMartin K. Petersen 			       (unsigned long)sector,
1750c6a44287SMartin K. Petersen 			       be16_to_cpu(sdt[i].guard_tag),
1751c6a44287SMartin K. Petersen 			       be16_to_cpu(csum));
1752c6a44287SMartin K. Petersen 			dif_errors++;
1753c6a44287SMartin K. Petersen 			return 0x01;
1754c6a44287SMartin K. Petersen 		}
1755c6a44287SMartin K. Petersen 
1756395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
1757c6a44287SMartin K. Petersen 		    be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) {
1758c6a44287SMartin K. Petersen 			printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1759c6a44287SMartin K. Petersen 			       __func__, (unsigned long)sector);
1760c6a44287SMartin K. Petersen 			dif_errors++;
1761c6a44287SMartin K. Petersen 			return 0x03;
1762c6a44287SMartin K. Petersen 		}
1763395cef03SMartin K. Petersen 
1764395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1765395cef03SMartin K. Petersen 		    be32_to_cpu(sdt[i].ref_tag) != ei_lba) {
1766395cef03SMartin K. Petersen 			printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1767395cef03SMartin K. Petersen 			       __func__, (unsigned long)sector);
1768395cef03SMartin K. Petersen 			dif_errors++;
1769395cef03SMartin K. Petersen 			return 0x03;
1770395cef03SMartin K. Petersen 		}
1771395cef03SMartin K. Petersen 
1772395cef03SMartin K. Petersen 		ei_lba++;
1773c6a44287SMartin K. Petersen 	}
1774c6a44287SMartin K. Petersen 
1775c6a44287SMartin K. Petersen 	resid = sectors * 8; /* Bytes of protection data to copy into sgl */
1776c6a44287SMartin K. Petersen 	sector = start_sec;
1777c6a44287SMartin K. Petersen 
1778c6a44287SMartin K. Petersen 	scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
1779c6a44287SMartin K. Petersen 		int len = min(psgl->length, resid);
1780c6a44287SMartin K. Petersen 
1781c6a44287SMartin K. Petersen 		paddr = kmap_atomic(sg_page(psgl), KM_IRQ0) + psgl->offset;
1782c6a44287SMartin K. Petersen 		memcpy(paddr, dif_storep + dif_offset(sector), len);
1783c6a44287SMartin K. Petersen 
1784c6a44287SMartin K. Petersen 		sector += len >> 3;
1785c6a44287SMartin K. Petersen 		if (sector >= sdebug_store_sectors) {
1786c6a44287SMartin K. Petersen 			/* Force wrap */
1787c6a44287SMartin K. Petersen 			tmp_sec = sector;
1788c6a44287SMartin K. Petersen 			sector = do_div(tmp_sec, sdebug_store_sectors);
1789c6a44287SMartin K. Petersen 		}
1790c6a44287SMartin K. Petersen 		resid -= len;
1791c6a44287SMartin K. Petersen 		kunmap_atomic(paddr, KM_IRQ0);
1792c6a44287SMartin K. Petersen 	}
1793c6a44287SMartin K. Petersen 
1794c6a44287SMartin K. Petersen 	dix_reads++;
1795c6a44287SMartin K. Petersen 
1796c6a44287SMartin K. Petersen 	return 0;
1797c6a44287SMartin K. Petersen }
1798c6a44287SMartin K. Petersen 
179919789100SFUJITA Tomonori static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
1800395cef03SMartin K. Petersen 		     unsigned int num, struct sdebug_dev_info *devip,
1801395cef03SMartin K. Petersen 		     u32 ei_lba)
180219789100SFUJITA Tomonori {
180319789100SFUJITA Tomonori 	unsigned long iflags;
180419789100SFUJITA Tomonori 	int ret;
180519789100SFUJITA Tomonori 
180619789100SFUJITA Tomonori 	ret = check_device_access_params(devip, lba, num);
180719789100SFUJITA Tomonori 	if (ret)
180819789100SFUJITA Tomonori 		return ret;
180919789100SFUJITA Tomonori 
18101da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
181132f7ef73SDouglas Gilbert 	    (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
1812c65b1445SDouglas Gilbert 	    ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1813c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
181432f7ef73SDouglas Gilbert 		mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
1815c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
1816c65b1445SDouglas Gilbert 		if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1817c65b1445SDouglas Gilbert 			devip->sense_buff[0] |= 0x80;	/* Valid bit */
181832f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
181932f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
1820c65b1445SDouglas Gilbert 			devip->sense_buff[3] = (ret >> 24) & 0xff;
1821c65b1445SDouglas Gilbert 			devip->sense_buff[4] = (ret >> 16) & 0xff;
1822c65b1445SDouglas Gilbert 			devip->sense_buff[5] = (ret >> 8) & 0xff;
1823c65b1445SDouglas Gilbert 			devip->sense_buff[6] = ret & 0xff;
1824c65b1445SDouglas Gilbert 		}
1825a87e3a67SDouglas Gilbert 	        scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
18261da177e4SLinus Torvalds 		return check_condition_result;
18271da177e4SLinus Torvalds 	}
1828c6a44287SMartin K. Petersen 
1829c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
1830c6a44287SMartin K. Petersen 	if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
1831395cef03SMartin K. Petersen 		int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
1832c6a44287SMartin K. Petersen 
1833c6a44287SMartin K. Petersen 		if (prot_ret) {
1834c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
1835c6a44287SMartin K. Petersen 			return illegal_condition_result;
1836c6a44287SMartin K. Petersen 		}
1837c6a44287SMartin K. Petersen 	}
1838c6a44287SMartin K. Petersen 
18391da177e4SLinus Torvalds 	read_lock_irqsave(&atomic_rw, iflags);
184019789100SFUJITA Tomonori 	ret = do_device_access(SCpnt, devip, lba, num, 0);
18411da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
18421da177e4SLinus Torvalds 	return ret;
18431da177e4SLinus Torvalds }
18441da177e4SLinus Torvalds 
1845c6a44287SMartin K. Petersen void dump_sector(unsigned char *buf, int len)
1846c6a44287SMartin K. Petersen {
1847c6a44287SMartin K. Petersen 	int i, j;
1848c6a44287SMartin K. Petersen 
1849c6a44287SMartin K. Petersen 	printk(KERN_ERR ">>> Sector Dump <<<\n");
1850c6a44287SMartin K. Petersen 
1851c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
1852c6a44287SMartin K. Petersen 		printk(KERN_ERR "%04d: ", i);
1853c6a44287SMartin K. Petersen 
1854c6a44287SMartin K. Petersen 		for (j = 0 ; j < 16 ; j++) {
1855c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
1856c6a44287SMartin K. Petersen 			if (c >= 0x20 && c < 0x7e)
1857c6a44287SMartin K. Petersen 				printk(" %c ", buf[i+j]);
1858c6a44287SMartin K. Petersen 			else
1859c6a44287SMartin K. Petersen 				printk("%02x ", buf[i+j]);
1860c6a44287SMartin K. Petersen 		}
1861c6a44287SMartin K. Petersen 
1862c6a44287SMartin K. Petersen 		printk("\n");
1863c6a44287SMartin K. Petersen 	}
1864c6a44287SMartin K. Petersen }
1865c6a44287SMartin K. Petersen 
1866c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
1867395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
1868c6a44287SMartin K. Petersen {
1869c6a44287SMartin K. Petersen 	int i, j, ret;
1870c6a44287SMartin K. Petersen 	struct sd_dif_tuple *sdt;
1871c6a44287SMartin K. Petersen 	struct scatterlist *dsgl = scsi_sglist(SCpnt);
1872c6a44287SMartin K. Petersen 	struct scatterlist *psgl = scsi_prot_sglist(SCpnt);
1873c6a44287SMartin K. Petersen 	void *daddr, *paddr;
1874c6a44287SMartin K. Petersen 	sector_t tmp_sec = start_sec;
1875c6a44287SMartin K. Petersen 	sector_t sector;
1876c6a44287SMartin K. Petersen 	int ppage_offset;
1877c6a44287SMartin K. Petersen 	unsigned short csum;
1878c6a44287SMartin K. Petersen 
1879c6a44287SMartin K. Petersen 	sector = do_div(tmp_sec, sdebug_store_sectors);
1880c6a44287SMartin K. Petersen 
1881c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
1882c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
1883c6a44287SMartin K. Petersen 
1884c6a44287SMartin K. Petersen 	paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) + psgl->offset;
1885c6a44287SMartin K. Petersen 	ppage_offset = 0;
1886c6a44287SMartin K. Petersen 
1887c6a44287SMartin K. Petersen 	/* For each data page */
1888c6a44287SMartin K. Petersen 	scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
1889c6a44287SMartin K. Petersen 		daddr = kmap_atomic(sg_page(dsgl), KM_IRQ0) + dsgl->offset;
1890c6a44287SMartin K. Petersen 
1891c6a44287SMartin K. Petersen 		/* For each sector-sized chunk in data page */
1892c6a44287SMartin K. Petersen 		for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) {
1893c6a44287SMartin K. Petersen 
1894c6a44287SMartin K. Petersen 			/* If we're at the end of the current
1895c6a44287SMartin K. Petersen 			 * protection page advance to the next one
1896c6a44287SMartin K. Petersen 			 */
1897c6a44287SMartin K. Petersen 			if (ppage_offset >= psgl->length) {
1898c6a44287SMartin K. Petersen 				kunmap_atomic(paddr, KM_IRQ1);
1899c6a44287SMartin K. Petersen 				psgl = sg_next(psgl);
1900c6a44287SMartin K. Petersen 				BUG_ON(psgl == NULL);
1901c6a44287SMartin K. Petersen 				paddr = kmap_atomic(sg_page(psgl), KM_IRQ1)
1902c6a44287SMartin K. Petersen 					+ psgl->offset;
1903c6a44287SMartin K. Petersen 				ppage_offset = 0;
1904c6a44287SMartin K. Petersen 			}
1905c6a44287SMartin K. Petersen 
1906c6a44287SMartin K. Petersen 			sdt = paddr + ppage_offset;
1907c6a44287SMartin K. Petersen 
1908c6a44287SMartin K. Petersen 			switch (scsi_debug_guard) {
1909c6a44287SMartin K. Petersen 			case 1:
1910c6a44287SMartin K. Petersen 				csum = ip_compute_csum(daddr,
1911c6a44287SMartin K. Petersen 						       scsi_debug_sector_size);
1912c6a44287SMartin K. Petersen 				break;
1913c6a44287SMartin K. Petersen 			case 0:
1914c6a44287SMartin K. Petersen 				csum = cpu_to_be16(crc_t10dif(daddr,
1915c6a44287SMartin K. Petersen 						      scsi_debug_sector_size));
1916c6a44287SMartin K. Petersen 				break;
1917c6a44287SMartin K. Petersen 			default:
1918c6a44287SMartin K. Petersen 				BUG();
1919c6a44287SMartin K. Petersen 				ret = 0;
1920c6a44287SMartin K. Petersen 				goto out;
1921c6a44287SMartin K. Petersen 			}
1922c6a44287SMartin K. Petersen 
1923c6a44287SMartin K. Petersen 			if (sdt->guard_tag != csum) {
1924c6a44287SMartin K. Petersen 				printk(KERN_ERR
1925c6a44287SMartin K. Petersen 				       "%s: GUARD check failed on sector %lu " \
1926c6a44287SMartin K. Petersen 				       "rcvd 0x%04x, calculated 0x%04x\n",
1927c6a44287SMartin K. Petersen 				       __func__, (unsigned long)sector,
1928c6a44287SMartin K. Petersen 				       be16_to_cpu(sdt->guard_tag),
1929c6a44287SMartin K. Petersen 				       be16_to_cpu(csum));
1930c6a44287SMartin K. Petersen 				ret = 0x01;
1931c6a44287SMartin K. Petersen 				dump_sector(daddr, scsi_debug_sector_size);
1932c6a44287SMartin K. Petersen 				goto out;
1933c6a44287SMartin K. Petersen 			}
1934c6a44287SMartin K. Petersen 
1935395cef03SMartin K. Petersen 			if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
1936c6a44287SMartin K. Petersen 			    be32_to_cpu(sdt->ref_tag)
1937c6a44287SMartin K. Petersen 			    != (start_sec & 0xffffffff)) {
1938c6a44287SMartin K. Petersen 				printk(KERN_ERR
1939c6a44287SMartin K. Petersen 				       "%s: REF check failed on sector %lu\n",
1940c6a44287SMartin K. Petersen 				       __func__, (unsigned long)sector);
1941c6a44287SMartin K. Petersen 				ret = 0x03;
1942c6a44287SMartin K. Petersen 				dump_sector(daddr, scsi_debug_sector_size);
1943c6a44287SMartin K. Petersen 				goto out;
1944c6a44287SMartin K. Petersen 			}
1945c6a44287SMartin K. Petersen 
1946395cef03SMartin K. Petersen 			if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1947395cef03SMartin K. Petersen 			    be32_to_cpu(sdt->ref_tag) != ei_lba) {
1948395cef03SMartin K. Petersen 				printk(KERN_ERR
1949395cef03SMartin K. Petersen 				       "%s: REF check failed on sector %lu\n",
1950395cef03SMartin K. Petersen 				       __func__, (unsigned long)sector);
1951395cef03SMartin K. Petersen 				ret = 0x03;
1952395cef03SMartin K. Petersen 				dump_sector(daddr, scsi_debug_sector_size);
1953395cef03SMartin K. Petersen 				goto out;
1954395cef03SMartin K. Petersen 			}
1955395cef03SMartin K. Petersen 
1956c6a44287SMartin K. Petersen 			/* Would be great to copy this in bigger
1957c6a44287SMartin K. Petersen 			 * chunks.  However, for the sake of
1958c6a44287SMartin K. Petersen 			 * correctness we need to verify each sector
1959c6a44287SMartin K. Petersen 			 * before writing it to "stable" storage
1960c6a44287SMartin K. Petersen 			 */
1961c6a44287SMartin K. Petersen 			memcpy(dif_storep + dif_offset(sector), sdt, 8);
1962c6a44287SMartin K. Petersen 
1963c6a44287SMartin K. Petersen 			sector++;
1964c6a44287SMartin K. Petersen 
1965c6a44287SMartin K. Petersen 			if (sector == sdebug_store_sectors)
1966c6a44287SMartin K. Petersen 				sector = 0;	/* Force wrap */
1967c6a44287SMartin K. Petersen 
1968c6a44287SMartin K. Petersen 			start_sec++;
1969395cef03SMartin K. Petersen 			ei_lba++;
1970c6a44287SMartin K. Petersen 			daddr += scsi_debug_sector_size;
1971c6a44287SMartin K. Petersen 			ppage_offset += sizeof(struct sd_dif_tuple);
1972c6a44287SMartin K. Petersen 		}
1973c6a44287SMartin K. Petersen 
1974c6a44287SMartin K. Petersen 		kunmap_atomic(daddr, KM_IRQ0);
1975c6a44287SMartin K. Petersen 	}
1976c6a44287SMartin K. Petersen 
1977c6a44287SMartin K. Petersen 	kunmap_atomic(paddr, KM_IRQ1);
1978c6a44287SMartin K. Petersen 
1979c6a44287SMartin K. Petersen 	dix_writes++;
1980c6a44287SMartin K. Petersen 
1981c6a44287SMartin K. Petersen 	return 0;
1982c6a44287SMartin K. Petersen 
1983c6a44287SMartin K. Petersen out:
1984c6a44287SMartin K. Petersen 	dif_errors++;
1985c6a44287SMartin K. Petersen 	kunmap_atomic(daddr, KM_IRQ0);
1986c6a44287SMartin K. Petersen 	kunmap_atomic(paddr, KM_IRQ1);
1987c6a44287SMartin K. Petersen 	return ret;
1988c6a44287SMartin K. Petersen }
1989c6a44287SMartin K. Petersen 
199044d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
199144d92694SMartin K. Petersen {
199244d92694SMartin K. Petersen 	unsigned int granularity, alignment, mapped;
199344d92694SMartin K. Petersen 	sector_t block, next, end;
199444d92694SMartin K. Petersen 
199544d92694SMartin K. Petersen 	granularity = scsi_debug_unmap_granularity;
199644d92694SMartin K. Petersen 	alignment = granularity - scsi_debug_unmap_alignment;
199744d92694SMartin K. Petersen 	block = lba + alignment;
199844d92694SMartin K. Petersen 	do_div(block, granularity);
199944d92694SMartin K. Petersen 
200044d92694SMartin K. Petersen 	mapped = test_bit(block, map_storep);
200144d92694SMartin K. Petersen 
200244d92694SMartin K. Petersen 	if (mapped)
200344d92694SMartin K. Petersen 		next = find_next_zero_bit(map_storep, map_size, block);
200444d92694SMartin K. Petersen 	else
200544d92694SMartin K. Petersen 		next = find_next_bit(map_storep, map_size, block);
200644d92694SMartin K. Petersen 
200744d92694SMartin K. Petersen 	end = next * granularity - scsi_debug_unmap_alignment;
200844d92694SMartin K. Petersen 	*num = end - lba;
200944d92694SMartin K. Petersen 
201044d92694SMartin K. Petersen 	return mapped;
201144d92694SMartin K. Petersen }
201244d92694SMartin K. Petersen 
201344d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
201444d92694SMartin K. Petersen {
201544d92694SMartin K. Petersen 	unsigned int granularity, alignment;
201644d92694SMartin K. Petersen 	sector_t end = lba + len;
201744d92694SMartin K. Petersen 
201844d92694SMartin K. Petersen 	granularity = scsi_debug_unmap_granularity;
201944d92694SMartin K. Petersen 	alignment = granularity - scsi_debug_unmap_alignment;
202044d92694SMartin K. Petersen 
202144d92694SMartin K. Petersen 	while (lba < end) {
202244d92694SMartin K. Petersen 		sector_t block, rem;
202344d92694SMartin K. Petersen 
202444d92694SMartin K. Petersen 		block = lba + alignment;
202544d92694SMartin K. Petersen 		rem = do_div(block, granularity);
202644d92694SMartin K. Petersen 
20279ab98f57SFUJITA Tomonori 		if (block < map_size)
202844d92694SMartin K. Petersen 			set_bit(block, map_storep);
202944d92694SMartin K. Petersen 
203044d92694SMartin K. Petersen 		lba += granularity - rem;
203144d92694SMartin K. Petersen 	}
203244d92694SMartin K. Petersen }
203344d92694SMartin K. Petersen 
203444d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
203544d92694SMartin K. Petersen {
203644d92694SMartin K. Petersen 	unsigned int granularity, alignment;
203744d92694SMartin K. Petersen 	sector_t end = lba + len;
203844d92694SMartin K. Petersen 
203944d92694SMartin K. Petersen 	granularity = scsi_debug_unmap_granularity;
204044d92694SMartin K. Petersen 	alignment = granularity - scsi_debug_unmap_alignment;
204144d92694SMartin K. Petersen 
204244d92694SMartin K. Petersen 	while (lba < end) {
204344d92694SMartin K. Petersen 		sector_t block, rem;
204444d92694SMartin K. Petersen 
204544d92694SMartin K. Petersen 		block = lba + alignment;
204644d92694SMartin K. Petersen 		rem = do_div(block, granularity);
204744d92694SMartin K. Petersen 
20489ab98f57SFUJITA Tomonori 		if (rem == 0 && lba + granularity <= end &&
20499ab98f57SFUJITA Tomonori 		    block < map_size)
205044d92694SMartin K. Petersen 			clear_bit(block, map_storep);
205144d92694SMartin K. Petersen 
205244d92694SMartin K. Petersen 		lba += granularity - rem;
205344d92694SMartin K. Petersen 	}
205444d92694SMartin K. Petersen }
205544d92694SMartin K. Petersen 
2056c65b1445SDouglas Gilbert static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
2057395cef03SMartin K. Petersen 		      unsigned int num, struct sdebug_dev_info *devip,
2058395cef03SMartin K. Petersen 		      u32 ei_lba)
20591da177e4SLinus Torvalds {
20601da177e4SLinus Torvalds 	unsigned long iflags;
206119789100SFUJITA Tomonori 	int ret;
20621da177e4SLinus Torvalds 
206319789100SFUJITA Tomonori 	ret = check_device_access_params(devip, lba, num);
206419789100SFUJITA Tomonori 	if (ret)
206519789100SFUJITA Tomonori 		return ret;
20661da177e4SLinus Torvalds 
2067c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2068c6a44287SMartin K. Petersen 	if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
2069395cef03SMartin K. Petersen 		int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
2070c6a44287SMartin K. Petersen 
2071c6a44287SMartin K. Petersen 		if (prot_ret) {
2072c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
2073c6a44287SMartin K. Petersen 			return illegal_condition_result;
2074c6a44287SMartin K. Petersen 		}
2075c6a44287SMartin K. Petersen 	}
2076c6a44287SMartin K. Petersen 
20771da177e4SLinus Torvalds 	write_lock_irqsave(&atomic_rw, iflags);
207819789100SFUJITA Tomonori 	ret = do_device_access(SCpnt, devip, lba, num, 1);
207944d92694SMartin K. Petersen 	if (scsi_debug_unmap_granularity)
208044d92694SMartin K. Petersen 		map_region(lba, num);
20811da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
208219789100SFUJITA Tomonori 	if (-1 == ret)
20831da177e4SLinus Torvalds 		return (DID_ERROR << 16);
2084597136abSMartin K. Petersen 	else if ((ret < (num * scsi_debug_sector_size)) &&
20851da177e4SLinus Torvalds 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
2086c65b1445SDouglas Gilbert 		printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
2087597136abSMartin K. Petersen 		       " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
208844d92694SMartin K. Petersen 
20891da177e4SLinus Torvalds 	return 0;
20901da177e4SLinus Torvalds }
20911da177e4SLinus Torvalds 
209244d92694SMartin K. Petersen static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,
209344d92694SMartin K. Petersen 		      unsigned int num, struct sdebug_dev_info *devip,
209444d92694SMartin K. Petersen 			   u32 ei_lba, unsigned int unmap)
209544d92694SMartin K. Petersen {
209644d92694SMartin K. Petersen 	unsigned long iflags;
209744d92694SMartin K. Petersen 	unsigned long long i;
209844d92694SMartin K. Petersen 	int ret;
209944d92694SMartin K. Petersen 
210044d92694SMartin K. Petersen 	ret = check_device_access_params(devip, lba, num);
210144d92694SMartin K. Petersen 	if (ret)
210244d92694SMartin K. Petersen 		return ret;
210344d92694SMartin K. Petersen 
21045b94e232SMartin K. Petersen 	if (num > scsi_debug_write_same_length) {
21055b94e232SMartin K. Petersen 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
21065b94e232SMartin K. Petersen 				0);
21075b94e232SMartin K. Petersen 		return check_condition_result;
21085b94e232SMartin K. Petersen 	}
21095b94e232SMartin K. Petersen 
211044d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
211144d92694SMartin K. Petersen 
211244d92694SMartin K. Petersen 	if (unmap && scsi_debug_unmap_granularity) {
211344d92694SMartin K. Petersen 		unmap_region(lba, num);
211444d92694SMartin K. Petersen 		goto out;
211544d92694SMartin K. Petersen 	}
211644d92694SMartin K. Petersen 
211744d92694SMartin K. Petersen 	/* Else fetch one logical block */
211844d92694SMartin K. Petersen 	ret = fetch_to_dev_buffer(scmd,
211944d92694SMartin K. Petersen 				  fake_storep + (lba * scsi_debug_sector_size),
212044d92694SMartin K. Petersen 				  scsi_debug_sector_size);
212144d92694SMartin K. Petersen 
212244d92694SMartin K. Petersen 	if (-1 == ret) {
212344d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
212444d92694SMartin K. Petersen 		return (DID_ERROR << 16);
212544d92694SMartin K. Petersen 	} else if ((ret < (num * scsi_debug_sector_size)) &&
212644d92694SMartin K. Petersen 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
212744d92694SMartin K. Petersen 		printk(KERN_INFO "scsi_debug: write same: cdb indicated=%u, "
212844d92694SMartin K. Petersen 		       " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
212944d92694SMartin K. Petersen 
213044d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
213144d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
213244d92694SMartin K. Petersen 		memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size),
213344d92694SMartin K. Petersen 		       fake_storep + (lba * scsi_debug_sector_size),
213444d92694SMartin K. Petersen 		       scsi_debug_sector_size);
213544d92694SMartin K. Petersen 
213644d92694SMartin K. Petersen 	if (scsi_debug_unmap_granularity)
213744d92694SMartin K. Petersen 		map_region(lba, num);
213844d92694SMartin K. Petersen out:
213944d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
214044d92694SMartin K. Petersen 
214144d92694SMartin K. Petersen 	return 0;
214244d92694SMartin K. Petersen }
214344d92694SMartin K. Petersen 
214444d92694SMartin K. Petersen struct unmap_block_desc {
214544d92694SMartin K. Petersen 	__be64	lba;
214644d92694SMartin K. Petersen 	__be32	blocks;
214744d92694SMartin K. Petersen 	__be32	__reserved;
214844d92694SMartin K. Petersen };
214944d92694SMartin K. Petersen 
215044d92694SMartin K. Petersen static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
215144d92694SMartin K. Petersen {
215244d92694SMartin K. Petersen 	unsigned char *buf;
215344d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
215444d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
215544d92694SMartin K. Petersen 	int ret;
215644d92694SMartin K. Petersen 
215744d92694SMartin K. Petersen 	ret = check_readiness(scmd, 1, devip);
215844d92694SMartin K. Petersen 	if (ret)
215944d92694SMartin K. Petersen 		return ret;
216044d92694SMartin K. Petersen 
216144d92694SMartin K. Petersen 	payload_len = get_unaligned_be16(&scmd->cmnd[7]);
216244d92694SMartin K. Petersen 	BUG_ON(scsi_bufflen(scmd) != payload_len);
216344d92694SMartin K. Petersen 
216444d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
216544d92694SMartin K. Petersen 
216644d92694SMartin K. Petersen 	buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC);
216744d92694SMartin K. Petersen 	if (!buf)
216844d92694SMartin K. Petersen 		return check_condition_result;
216944d92694SMartin K. Petersen 
217044d92694SMartin K. Petersen 	scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
217144d92694SMartin K. Petersen 
217244d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
217344d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
217444d92694SMartin K. Petersen 
217544d92694SMartin K. Petersen 	desc = (void *)&buf[8];
217644d92694SMartin K. Petersen 
217744d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
217844d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
217944d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
218044d92694SMartin K. Petersen 
218144d92694SMartin K. Petersen 		ret = check_device_access_params(devip, lba, num);
218244d92694SMartin K. Petersen 		if (ret)
218344d92694SMartin K. Petersen 			goto out;
218444d92694SMartin K. Petersen 
218544d92694SMartin K. Petersen 		unmap_region(lba, num);
218644d92694SMartin K. Petersen 	}
218744d92694SMartin K. Petersen 
218844d92694SMartin K. Petersen 	ret = 0;
218944d92694SMartin K. Petersen 
219044d92694SMartin K. Petersen out:
219144d92694SMartin K. Petersen 	kfree(buf);
219244d92694SMartin K. Petersen 
219344d92694SMartin K. Petersen 	return ret;
219444d92694SMartin K. Petersen }
219544d92694SMartin K. Petersen 
219644d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
219744d92694SMartin K. Petersen 
219844d92694SMartin K. Petersen static int resp_get_lba_status(struct scsi_cmnd * scmd,
219944d92694SMartin K. Petersen 			       struct sdebug_dev_info * devip)
220044d92694SMartin K. Petersen {
220144d92694SMartin K. Petersen 	unsigned long long lba;
220244d92694SMartin K. Petersen 	unsigned int alloc_len, mapped, num;
220344d92694SMartin K. Petersen 	unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN];
220444d92694SMartin K. Petersen 	int ret;
220544d92694SMartin K. Petersen 
220644d92694SMartin K. Petersen 	ret = check_readiness(scmd, 1, devip);
220744d92694SMartin K. Petersen 	if (ret)
220844d92694SMartin K. Petersen 		return ret;
220944d92694SMartin K. Petersen 
221044d92694SMartin K. Petersen 	lba = get_unaligned_be64(&scmd->cmnd[2]);
221144d92694SMartin K. Petersen 	alloc_len = get_unaligned_be32(&scmd->cmnd[10]);
221244d92694SMartin K. Petersen 
221344d92694SMartin K. Petersen 	if (alloc_len < 24)
221444d92694SMartin K. Petersen 		return 0;
221544d92694SMartin K. Petersen 
221644d92694SMartin K. Petersen 	ret = check_device_access_params(devip, lba, 1);
221744d92694SMartin K. Petersen 	if (ret)
221844d92694SMartin K. Petersen 		return ret;
221944d92694SMartin K. Petersen 
222044d92694SMartin K. Petersen 	mapped = map_state(lba, &num);
222144d92694SMartin K. Petersen 
222244d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
2223de13e965SDouglas Gilbert 	put_unaligned_be32(20, &arr[0]);	/* Parameter Data Length */
222444d92694SMartin K. Petersen 	put_unaligned_be64(lba, &arr[8]);	/* LBA */
222544d92694SMartin K. Petersen 	put_unaligned_be32(num, &arr[16]);	/* Number of blocks */
222644d92694SMartin K. Petersen 	arr[20] = !mapped;			/* mapped = 0, unmapped = 1 */
222744d92694SMartin K. Petersen 
222844d92694SMartin K. Petersen 	return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN);
222944d92694SMartin K. Petersen }
223044d92694SMartin K. Petersen 
2231c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256
22321da177e4SLinus Torvalds 
22331da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp,
22341da177e4SLinus Torvalds 			    struct sdebug_dev_info * devip)
22351da177e4SLinus Torvalds {
22361da177e4SLinus Torvalds 	unsigned int alloc_len;
2237c65b1445SDouglas Gilbert 	int lun_cnt, i, upper, num, n, wlun, lun;
22381da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
22391da177e4SLinus Torvalds 	int select_report = (int)cmd[2];
22401da177e4SLinus Torvalds 	struct scsi_lun *one_lun;
22411da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_RLUN_ARR_SZ];
2242c65b1445SDouglas Gilbert 	unsigned char * max_addr;
22431da177e4SLinus Torvalds 
22441da177e4SLinus Torvalds 	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
2245c65b1445SDouglas Gilbert 	if ((alloc_len < 4) || (select_report > 2)) {
22461da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
22471da177e4SLinus Torvalds 			       	0);
22481da177e4SLinus Torvalds 		return check_condition_result;
22491da177e4SLinus Torvalds 	}
22501da177e4SLinus Torvalds 	/* can produce response with up to 16k luns (lun 0 to lun 16383) */
22511da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
22521da177e4SLinus Torvalds 	lun_cnt = scsi_debug_max_luns;
2253c65b1445SDouglas Gilbert 	if (1 == select_report)
2254c65b1445SDouglas Gilbert 		lun_cnt = 0;
2255c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
2256c65b1445SDouglas Gilbert 		--lun_cnt;
2257c65b1445SDouglas Gilbert 	wlun = (select_report > 0) ? 1 : 0;
2258c65b1445SDouglas Gilbert 	num = lun_cnt + wlun;
2259c65b1445SDouglas Gilbert 	arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
2260c65b1445SDouglas Gilbert 	arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
2261c65b1445SDouglas Gilbert 	n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
2262c65b1445SDouglas Gilbert 			    sizeof(struct scsi_lun)), num);
2263c65b1445SDouglas Gilbert 	if (n < num) {
2264c65b1445SDouglas Gilbert 		wlun = 0;
2265c65b1445SDouglas Gilbert 		lun_cnt = n;
2266c65b1445SDouglas Gilbert 	}
22671da177e4SLinus Torvalds 	one_lun = (struct scsi_lun *) &arr[8];
2268c65b1445SDouglas Gilbert 	max_addr = arr + SDEBUG_RLUN_ARR_SZ;
2269c65b1445SDouglas Gilbert 	for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
2270c65b1445SDouglas Gilbert              ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
2271c65b1445SDouglas Gilbert 	     i++, lun++) {
2272c65b1445SDouglas Gilbert 		upper = (lun >> 8) & 0x3f;
22731da177e4SLinus Torvalds 		if (upper)
22741da177e4SLinus Torvalds 			one_lun[i].scsi_lun[0] =
22751da177e4SLinus Torvalds 			    (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
2276c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = lun & 0xff;
22771da177e4SLinus Torvalds 	}
2278c65b1445SDouglas Gilbert 	if (wlun) {
2279c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
2280c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
2281c65b1445SDouglas Gilbert 		i++;
2282c65b1445SDouglas Gilbert 	}
2283c65b1445SDouglas Gilbert 	alloc_len = (unsigned char *)(one_lun + i) - arr;
22841da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr,
22851da177e4SLinus Torvalds 				    min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
22861da177e4SLinus Torvalds }
22871da177e4SLinus Torvalds 
2288c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
2289c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
2290c639d14eSFUJITA Tomonori {
2291c639d14eSFUJITA Tomonori 	int i, j, ret = -1;
2292c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
2293c639d14eSFUJITA Tomonori 	unsigned int offset;
2294c639d14eSFUJITA Tomonori 	struct scatterlist *sg;
2295c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
2296c639d14eSFUJITA Tomonori 
2297c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
2298c639d14eSFUJITA Tomonori 	buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
2299c639d14eSFUJITA Tomonori 	if (!buf)
2300c639d14eSFUJITA Tomonori 		return ret;
2301c639d14eSFUJITA Tomonori 
230221a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
2303c639d14eSFUJITA Tomonori 
2304c639d14eSFUJITA Tomonori 	offset = 0;
2305c639d14eSFUJITA Tomonori 	for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
2306c639d14eSFUJITA Tomonori 		kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
2307c639d14eSFUJITA Tomonori 		if (!kaddr)
2308c639d14eSFUJITA Tomonori 			goto out;
2309c639d14eSFUJITA Tomonori 
2310c639d14eSFUJITA Tomonori 		for (j = 0; j < sg->length; j++)
2311c639d14eSFUJITA Tomonori 			*(kaddr + sg->offset + j) ^= *(buf + offset + j);
2312c639d14eSFUJITA Tomonori 
2313c639d14eSFUJITA Tomonori 		offset += sg->length;
2314c639d14eSFUJITA Tomonori 		kunmap_atomic(kaddr, KM_USER0);
2315c639d14eSFUJITA Tomonori 	}
2316c639d14eSFUJITA Tomonori 	ret = 0;
2317c639d14eSFUJITA Tomonori out:
2318c639d14eSFUJITA Tomonori 	kfree(buf);
2319c639d14eSFUJITA Tomonori 
2320c639d14eSFUJITA Tomonori 	return ret;
2321c639d14eSFUJITA Tomonori }
2322c639d14eSFUJITA Tomonori 
23231da177e4SLinus Torvalds /* When timer goes off this function is called. */
23241da177e4SLinus Torvalds static void timer_intr_handler(unsigned long indx)
23251da177e4SLinus Torvalds {
23261da177e4SLinus Torvalds 	struct sdebug_queued_cmd * sqcp;
23271da177e4SLinus Torvalds 	unsigned long iflags;
23281da177e4SLinus Torvalds 
232978d4e5a0SDouglas Gilbert 	if (indx >= scsi_debug_max_queue) {
23301da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
23311da177e4SLinus Torvalds 		       "large\n");
23321da177e4SLinus Torvalds 		return;
23331da177e4SLinus Torvalds 	}
23341da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
23351da177e4SLinus Torvalds 	sqcp = &queued_arr[(int)indx];
23361da177e4SLinus Torvalds 	if (! sqcp->in_use) {
23371da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
23381da177e4SLinus Torvalds 		       "interrupt\n");
23391da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
23401da177e4SLinus Torvalds 		return;
23411da177e4SLinus Torvalds 	}
23421da177e4SLinus Torvalds 	sqcp->in_use = 0;
23431da177e4SLinus Torvalds 	if (sqcp->done_funct) {
23441da177e4SLinus Torvalds 		sqcp->a_cmnd->result = sqcp->scsi_result;
23451da177e4SLinus Torvalds 		sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
23461da177e4SLinus Torvalds 	}
23471da177e4SLinus Torvalds 	sqcp->done_funct = NULL;
23481da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
23491da177e4SLinus Torvalds }
23501da177e4SLinus Torvalds 
23511da177e4SLinus Torvalds 
23528dea0d02SFUJITA Tomonori static struct sdebug_dev_info *
23538dea0d02SFUJITA Tomonori sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
23545cb2fc06SFUJITA Tomonori {
23555cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
23565cb2fc06SFUJITA Tomonori 
23575cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
23585cb2fc06SFUJITA Tomonori 	if (devip) {
23595cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
23605cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
23615cb2fc06SFUJITA Tomonori 	}
23625cb2fc06SFUJITA Tomonori 	return devip;
23635cb2fc06SFUJITA Tomonori }
23645cb2fc06SFUJITA Tomonori 
23651da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
23661da177e4SLinus Torvalds {
23671da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
23681da177e4SLinus Torvalds 	struct sdebug_dev_info * open_devip = NULL;
23691da177e4SLinus Torvalds 	struct sdebug_dev_info * devip =
23701da177e4SLinus Torvalds 			(struct sdebug_dev_info *)sdev->hostdata;
23711da177e4SLinus Torvalds 
23721da177e4SLinus Torvalds 	if (devip)
23731da177e4SLinus Torvalds 		return devip;
2374d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
23751da177e4SLinus Torvalds 	if (!sdbg_host) {
23761da177e4SLinus Torvalds                 printk(KERN_ERR "Host info NULL\n");
23771da177e4SLinus Torvalds 		return NULL;
23781da177e4SLinus Torvalds         }
23791da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
23801da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
23811da177e4SLinus Torvalds                     (devip->target == sdev->id) &&
23821da177e4SLinus Torvalds                     (devip->lun == sdev->lun))
23831da177e4SLinus Torvalds                         return devip;
23841da177e4SLinus Torvalds 		else {
23851da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
23861da177e4SLinus Torvalds 				open_devip = devip;
23871da177e4SLinus Torvalds 		}
23881da177e4SLinus Torvalds 	}
23895cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
23905cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
23915cb2fc06SFUJITA Tomonori 		if (!open_devip) {
23921da177e4SLinus Torvalds 			printk(KERN_ERR "%s: out of memory at line %d\n",
2393cadbd4a5SHarvey Harrison 				__func__, __LINE__);
23941da177e4SLinus Torvalds 			return NULL;
23951da177e4SLinus Torvalds 		}
23961da177e4SLinus Torvalds 	}
2397a75869d1SFUJITA Tomonori 
23981da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
23991da177e4SLinus Torvalds 	open_devip->target = sdev->id;
24001da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
24011da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
24021da177e4SLinus Torvalds 	open_devip->reset = 1;
24031da177e4SLinus Torvalds 	open_devip->used = 1;
24041da177e4SLinus Torvalds 	memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
24051da177e4SLinus Torvalds 	if (scsi_debug_dsense)
24061da177e4SLinus Torvalds 		open_devip->sense_buff[0] = 0x72;
24071da177e4SLinus Torvalds 	else {
24081da177e4SLinus Torvalds 		open_devip->sense_buff[0] = 0x70;
24091da177e4SLinus Torvalds 		open_devip->sense_buff[7] = 0xa;
24101da177e4SLinus Torvalds 	}
2411c65b1445SDouglas Gilbert 	if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2412c65b1445SDouglas Gilbert 		open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
2413a75869d1SFUJITA Tomonori 
24141da177e4SLinus Torvalds 	return open_devip;
24151da177e4SLinus Torvalds }
24161da177e4SLinus Torvalds 
24178dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
24181da177e4SLinus Torvalds {
24198dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
24208dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
24218dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
242275ad23bcSNick Piggin 	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
24238dea0d02SFUJITA Tomonori 	return 0;
24248dea0d02SFUJITA Tomonori }
24251da177e4SLinus Torvalds 
24268dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
24278dea0d02SFUJITA Tomonori {
24288dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip;
2429a34c4e98SFUJITA Tomonori 
24301da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
24318dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
24328dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
24338dea0d02SFUJITA Tomonori 	if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
24348dea0d02SFUJITA Tomonori 		sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
24358dea0d02SFUJITA Tomonori 	devip = devInfoReg(sdp);
24368dea0d02SFUJITA Tomonori 	if (NULL == devip)
24378dea0d02SFUJITA Tomonori 		return 1;	/* no resources, will be marked offline */
24388dea0d02SFUJITA Tomonori 	sdp->hostdata = devip;
24398dea0d02SFUJITA Tomonori 	if (sdp->host->cmd_per_lun)
24408dea0d02SFUJITA Tomonori 		scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
24418dea0d02SFUJITA Tomonori 					sdp->host->cmd_per_lun);
24428dea0d02SFUJITA Tomonori 	blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
244378d4e5a0SDouglas Gilbert 	if (scsi_debug_no_uld)
244478d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
24458dea0d02SFUJITA Tomonori 	return 0;
24468dea0d02SFUJITA Tomonori }
24478dea0d02SFUJITA Tomonori 
24488dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
24498dea0d02SFUJITA Tomonori {
24508dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
24518dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
24528dea0d02SFUJITA Tomonori 
24538dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
24548dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
24558dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
24568dea0d02SFUJITA Tomonori 	if (devip) {
245725985edcSLucas De Marchi 		/* make this slot available for re-use */
24588dea0d02SFUJITA Tomonori 		devip->used = 0;
24598dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
24608dea0d02SFUJITA Tomonori 	}
24618dea0d02SFUJITA Tomonori }
24628dea0d02SFUJITA Tomonori 
24638dea0d02SFUJITA Tomonori /* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
24648dea0d02SFUJITA Tomonori static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
24658dea0d02SFUJITA Tomonori {
24668dea0d02SFUJITA Tomonori 	unsigned long iflags;
24678dea0d02SFUJITA Tomonori 	int k;
24688dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
24698dea0d02SFUJITA Tomonori 
24708dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
247178d4e5a0SDouglas Gilbert 	for (k = 0; k < scsi_debug_max_queue; ++k) {
24728dea0d02SFUJITA Tomonori 		sqcp = &queued_arr[k];
24738dea0d02SFUJITA Tomonori 		if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
24748dea0d02SFUJITA Tomonori 			del_timer_sync(&sqcp->cmnd_timer);
24758dea0d02SFUJITA Tomonori 			sqcp->in_use = 0;
24768dea0d02SFUJITA Tomonori 			sqcp->a_cmnd = NULL;
24778dea0d02SFUJITA Tomonori 			break;
24788dea0d02SFUJITA Tomonori 		}
24798dea0d02SFUJITA Tomonori 	}
24808dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
248178d4e5a0SDouglas Gilbert 	return (k < scsi_debug_max_queue) ? 1 : 0;
24828dea0d02SFUJITA Tomonori }
24838dea0d02SFUJITA Tomonori 
24848dea0d02SFUJITA Tomonori /* Deletes (stops) timers of all queued commands */
24858dea0d02SFUJITA Tomonori static void stop_all_queued(void)
24868dea0d02SFUJITA Tomonori {
24878dea0d02SFUJITA Tomonori 	unsigned long iflags;
24888dea0d02SFUJITA Tomonori 	int k;
24898dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
24908dea0d02SFUJITA Tomonori 
24918dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
249278d4e5a0SDouglas Gilbert 	for (k = 0; k < scsi_debug_max_queue; ++k) {
24938dea0d02SFUJITA Tomonori 		sqcp = &queued_arr[k];
24948dea0d02SFUJITA Tomonori 		if (sqcp->in_use && sqcp->a_cmnd) {
24958dea0d02SFUJITA Tomonori 			del_timer_sync(&sqcp->cmnd_timer);
24968dea0d02SFUJITA Tomonori 			sqcp->in_use = 0;
24978dea0d02SFUJITA Tomonori 			sqcp->a_cmnd = NULL;
24988dea0d02SFUJITA Tomonori 		}
24998dea0d02SFUJITA Tomonori 	}
25008dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
25011da177e4SLinus Torvalds }
25021da177e4SLinus Torvalds 
25031da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
25041da177e4SLinus Torvalds {
25051da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25061da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: abort\n");
25071da177e4SLinus Torvalds 	++num_aborts;
25081da177e4SLinus Torvalds 	stop_queued_cmnd(SCpnt);
25091da177e4SLinus Torvalds 	return SUCCESS;
25101da177e4SLinus Torvalds }
25111da177e4SLinus Torvalds 
25121da177e4SLinus Torvalds static int scsi_debug_biosparam(struct scsi_device *sdev,
25131da177e4SLinus Torvalds 		struct block_device * bdev, sector_t capacity, int *info)
25141da177e4SLinus Torvalds {
25151da177e4SLinus Torvalds 	int res;
25161da177e4SLinus Torvalds 	unsigned char *buf;
25171da177e4SLinus Torvalds 
25181da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25191da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: biosparam\n");
25201da177e4SLinus Torvalds 	buf = scsi_bios_ptable(bdev);
25211da177e4SLinus Torvalds 	if (buf) {
25221da177e4SLinus Torvalds 		res = scsi_partsize(buf, capacity,
25231da177e4SLinus Torvalds 				    &info[2], &info[0], &info[1]);
25241da177e4SLinus Torvalds 		kfree(buf);
25251da177e4SLinus Torvalds 		if (! res)
25261da177e4SLinus Torvalds 			return res;
25271da177e4SLinus Torvalds 	}
25281da177e4SLinus Torvalds 	info[0] = sdebug_heads;
25291da177e4SLinus Torvalds 	info[1] = sdebug_sectors_per;
25301da177e4SLinus Torvalds 	info[2] = sdebug_cylinders_per;
25311da177e4SLinus Torvalds 	return 0;
25321da177e4SLinus Torvalds }
25331da177e4SLinus Torvalds 
25341da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
25351da177e4SLinus Torvalds {
25361da177e4SLinus Torvalds 	struct sdebug_dev_info * devip;
25371da177e4SLinus Torvalds 
25381da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25391da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: device_reset\n");
25401da177e4SLinus Torvalds 	++num_dev_resets;
25411da177e4SLinus Torvalds 	if (SCpnt) {
25421da177e4SLinus Torvalds 		devip = devInfoReg(SCpnt->device);
25431da177e4SLinus Torvalds 		if (devip)
25441da177e4SLinus Torvalds 			devip->reset = 1;
25451da177e4SLinus Torvalds 	}
25461da177e4SLinus Torvalds 	return SUCCESS;
25471da177e4SLinus Torvalds }
25481da177e4SLinus Torvalds 
25491da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
25501da177e4SLinus Torvalds {
25511da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
25521da177e4SLinus Torvalds         struct sdebug_dev_info * dev_info;
25531da177e4SLinus Torvalds         struct scsi_device * sdp;
25541da177e4SLinus Torvalds         struct Scsi_Host * hp;
25551da177e4SLinus Torvalds 
25561da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25571da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: bus_reset\n");
25581da177e4SLinus Torvalds 	++num_bus_resets;
25591da177e4SLinus Torvalds 	if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
2560d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
25611da177e4SLinus Torvalds 		if (sdbg_host) {
25621da177e4SLinus Torvalds 			list_for_each_entry(dev_info,
25631da177e4SLinus Torvalds                                             &sdbg_host->dev_info_list,
25641da177e4SLinus Torvalds                                             dev_list)
25651da177e4SLinus Torvalds 				dev_info->reset = 1;
25661da177e4SLinus Torvalds 		}
25671da177e4SLinus Torvalds 	}
25681da177e4SLinus Torvalds 	return SUCCESS;
25691da177e4SLinus Torvalds }
25701da177e4SLinus Torvalds 
25711da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
25721da177e4SLinus Torvalds {
25731da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
25741da177e4SLinus Torvalds         struct sdebug_dev_info * dev_info;
25751da177e4SLinus Torvalds 
25761da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25771da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: host_reset\n");
25781da177e4SLinus Torvalds 	++num_host_resets;
25791da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
25801da177e4SLinus Torvalds         list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
25811da177e4SLinus Torvalds                 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
25821da177e4SLinus Torvalds                                     dev_list)
25831da177e4SLinus Torvalds                         dev_info->reset = 1;
25841da177e4SLinus Torvalds         }
25851da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
25861da177e4SLinus Torvalds 	stop_all_queued();
25871da177e4SLinus Torvalds 	return SUCCESS;
25881da177e4SLinus Torvalds }
25891da177e4SLinus Torvalds 
25901da177e4SLinus Torvalds /* Initializes timers in queued array */
25911da177e4SLinus Torvalds static void __init init_all_queued(void)
25921da177e4SLinus Torvalds {
25931da177e4SLinus Torvalds 	unsigned long iflags;
25941da177e4SLinus Torvalds 	int k;
25951da177e4SLinus Torvalds 	struct sdebug_queued_cmd * sqcp;
25961da177e4SLinus Torvalds 
25971da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
259878d4e5a0SDouglas Gilbert 	for (k = 0; k < scsi_debug_max_queue; ++k) {
25991da177e4SLinus Torvalds 		sqcp = &queued_arr[k];
26001da177e4SLinus Torvalds 		init_timer(&sqcp->cmnd_timer);
26011da177e4SLinus Torvalds 		sqcp->in_use = 0;
26021da177e4SLinus Torvalds 		sqcp->a_cmnd = NULL;
26031da177e4SLinus Torvalds 	}
26041da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
26051da177e4SLinus Torvalds }
26061da177e4SLinus Torvalds 
2607f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
26085f2578e5SFUJITA Tomonori 				      unsigned long store_size)
26091da177e4SLinus Torvalds {
26101da177e4SLinus Torvalds 	struct partition * pp;
26111da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
26121da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
26131da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
26141da177e4SLinus Torvalds 
26151da177e4SLinus Torvalds 	/* assume partition table already zeroed */
2616f58b0efbSFUJITA Tomonori 	if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
26171da177e4SLinus Torvalds 		return;
26181da177e4SLinus Torvalds 	if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
26191da177e4SLinus Torvalds 		scsi_debug_num_parts = SDEBUG_MAX_PARTS;
26201da177e4SLinus Torvalds 		printk(KERN_WARNING "scsi_debug:build_parts: reducing "
26211da177e4SLinus Torvalds 				    "partitions to %d\n", SDEBUG_MAX_PARTS);
26221da177e4SLinus Torvalds 	}
2623c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
26241da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
26251da177e4SLinus Torvalds 			   / scsi_debug_num_parts;
26261da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
26271da177e4SLinus Torvalds         starts[0] = sdebug_sectors_per;
26281da177e4SLinus Torvalds 	for (k = 1; k < scsi_debug_num_parts; ++k)
26291da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
26301da177e4SLinus Torvalds 			    * heads_by_sects;
26311da177e4SLinus Torvalds 	starts[scsi_debug_num_parts] = num_sectors;
26321da177e4SLinus Torvalds 	starts[scsi_debug_num_parts + 1] = 0;
26331da177e4SLinus Torvalds 
26341da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
26351da177e4SLinus Torvalds 	ramp[511] = 0xAA;
26361da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
26371da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
26381da177e4SLinus Torvalds 		start_sec = starts[k];
26391da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
26401da177e4SLinus Torvalds 		pp->boot_ind = 0;
26411da177e4SLinus Torvalds 
26421da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
26431da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
26441da177e4SLinus Torvalds 			   / sdebug_sectors_per;
26451da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
26461da177e4SLinus Torvalds 
26471da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
26481da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
26491da177e4SLinus Torvalds 			       / sdebug_sectors_per;
26501da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
26511da177e4SLinus Torvalds 
26521da177e4SLinus Torvalds 		pp->start_sect = start_sec;
26531da177e4SLinus Torvalds 		pp->nr_sects = end_sec - start_sec + 1;
26541da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
26551da177e4SLinus Torvalds 	}
26561da177e4SLinus Torvalds }
26571da177e4SLinus Torvalds 
26581da177e4SLinus Torvalds static int schedule_resp(struct scsi_cmnd * cmnd,
26591da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip,
26601da177e4SLinus Torvalds 			 done_funct_t done, int scsi_result, int delta_jiff)
26611da177e4SLinus Torvalds {
26621da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
26631da177e4SLinus Torvalds 		if (scsi_result) {
26641da177e4SLinus Torvalds 			struct scsi_device * sdp = cmnd->device;
26651da177e4SLinus Torvalds 
2666c65b1445SDouglas Gilbert 			printk(KERN_INFO "scsi_debug:    <%u %u %u %u> "
2667c65b1445SDouglas Gilbert 			       "non-zero result=0x%x\n", sdp->host->host_no,
2668c65b1445SDouglas Gilbert 			       sdp->channel, sdp->id, sdp->lun, scsi_result);
26691da177e4SLinus Torvalds 		}
26701da177e4SLinus Torvalds 	}
26711da177e4SLinus Torvalds 	if (cmnd && devip) {
26721da177e4SLinus Torvalds 		/* simulate autosense by this driver */
26731da177e4SLinus Torvalds 		if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
26741da177e4SLinus Torvalds 			memcpy(cmnd->sense_buffer, devip->sense_buff,
26751da177e4SLinus Torvalds 			       (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
26761da177e4SLinus Torvalds 			       SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
26771da177e4SLinus Torvalds 	}
26781da177e4SLinus Torvalds 	if (delta_jiff <= 0) {
26791da177e4SLinus Torvalds 		if (cmnd)
26801da177e4SLinus Torvalds 			cmnd->result = scsi_result;
26811da177e4SLinus Torvalds 		if (done)
26821da177e4SLinus Torvalds 			done(cmnd);
26831da177e4SLinus Torvalds 		return 0;
26841da177e4SLinus Torvalds 	} else {
26851da177e4SLinus Torvalds 		unsigned long iflags;
26861da177e4SLinus Torvalds 		int k;
26871da177e4SLinus Torvalds 		struct sdebug_queued_cmd * sqcp = NULL;
26881da177e4SLinus Torvalds 
26891da177e4SLinus Torvalds 		spin_lock_irqsave(&queued_arr_lock, iflags);
269078d4e5a0SDouglas Gilbert 		for (k = 0; k < scsi_debug_max_queue; ++k) {
26911da177e4SLinus Torvalds 			sqcp = &queued_arr[k];
26921da177e4SLinus Torvalds 			if (! sqcp->in_use)
26931da177e4SLinus Torvalds 				break;
26941da177e4SLinus Torvalds 		}
269578d4e5a0SDouglas Gilbert 		if (k >= scsi_debug_max_queue) {
26961da177e4SLinus Torvalds 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
26971da177e4SLinus Torvalds 			printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
26981da177e4SLinus Torvalds 			return 1;	/* report busy to mid level */
26991da177e4SLinus Torvalds 		}
27001da177e4SLinus Torvalds 		sqcp->in_use = 1;
27011da177e4SLinus Torvalds 		sqcp->a_cmnd = cmnd;
27021da177e4SLinus Torvalds 		sqcp->scsi_result = scsi_result;
27031da177e4SLinus Torvalds 		sqcp->done_funct = done;
27041da177e4SLinus Torvalds 		sqcp->cmnd_timer.function = timer_intr_handler;
27051da177e4SLinus Torvalds 		sqcp->cmnd_timer.data = k;
27061da177e4SLinus Torvalds 		sqcp->cmnd_timer.expires = jiffies + delta_jiff;
27071da177e4SLinus Torvalds 		add_timer(&sqcp->cmnd_timer);
27081da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
27091da177e4SLinus Torvalds 		if (cmnd)
27101da177e4SLinus Torvalds 			cmnd->result = 0;
27111da177e4SLinus Torvalds 		return 0;
27121da177e4SLinus Torvalds 	}
27131da177e4SLinus Torvalds }
271423183910SDouglas Gilbert /* Note: The following macros create attribute files in the
271523183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
271623183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
271723183910SDouglas Gilbert    as it can when the corresponding attribute in the
271823183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
271923183910SDouglas Gilbert  */
2720c65b1445SDouglas Gilbert module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
27215b94e232SMartin K. Petersen module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
2722c65b1445SDouglas Gilbert module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2723c65b1445SDouglas Gilbert module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
27245b94e232SMartin K. Petersen module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
27255b94e232SMartin K. Petersen module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
2726c65b1445SDouglas Gilbert module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2727c65b1445SDouglas Gilbert module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
272823183910SDouglas Gilbert module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
27295b94e232SMartin K. Petersen module_param_named(guard, scsi_debug_guard, int, S_IRUGO);
27305b94e232SMartin K. Petersen module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO);
27315b94e232SMartin K. Petersen module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO);
27325b94e232SMartin K. Petersen module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO);
27335b94e232SMartin K. Petersen module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
2734c65b1445SDouglas Gilbert module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
273578d4e5a0SDouglas Gilbert module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);
2736c65b1445SDouglas Gilbert module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
273778d4e5a0SDouglas Gilbert module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);
2738c65b1445SDouglas Gilbert module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2739c65b1445SDouglas Gilbert module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
27405b94e232SMartin K. Petersen module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO);
2741c65b1445SDouglas Gilbert module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
27425b94e232SMartin K. Petersen module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
2743c65b1445SDouglas Gilbert module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2744c65b1445SDouglas Gilbert module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
27455b94e232SMartin K. Petersen module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
27465b94e232SMartin K. Petersen module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
27475b94e232SMartin K. Petersen module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
27485b94e232SMartin K. Petersen module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
27495b94e232SMartin K. Petersen module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
2750c65b1445SDouglas Gilbert module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
275123183910SDouglas Gilbert module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
275223183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
27535b94e232SMartin K. Petersen module_param_named(write_same_length, scsi_debug_write_same_length, int,
27545b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
27551da177e4SLinus Torvalds 
27561da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
27571da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
27581da177e4SLinus Torvalds MODULE_LICENSE("GPL");
27591da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION);
27601da177e4SLinus Torvalds 
27611da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
27625b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
27631da177e4SLinus Torvalds MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
2764c65b1445SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
27655b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
27665b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
2767c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
2768beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
276923183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
27705b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
27715b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
27725b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
27735b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
27745b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
2775c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
277678d4e5a0SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to 255(def))");
2777c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
277878d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
27791da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
2780c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
27815b94e232SMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
27826f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
27835b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
27841da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
27851da177e4SLinus Torvalds MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
2786ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
27875b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
27885b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
27896014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
27906014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
27915b94e232SMartin K. Petersen MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
27925b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
27935b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
27941da177e4SLinus Torvalds 
27951da177e4SLinus Torvalds static char sdebug_info[256];
27961da177e4SLinus Torvalds 
27971da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp)
27981da177e4SLinus Torvalds {
27991da177e4SLinus Torvalds 	sprintf(sdebug_info, "scsi_debug, version %s [%s], "
28001da177e4SLinus Torvalds 		"dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
28011da177e4SLinus Torvalds 		scsi_debug_version_date, scsi_debug_dev_size_mb,
28021da177e4SLinus Torvalds 		scsi_debug_opts);
28031da177e4SLinus Torvalds 	return sdebug_info;
28041da177e4SLinus Torvalds }
28051da177e4SLinus Torvalds 
28061da177e4SLinus Torvalds /* scsi_debug_proc_info
28071da177e4SLinus Torvalds  * Used if the driver currently has no own support for /proc/scsi
28081da177e4SLinus Torvalds  */
28091da177e4SLinus Torvalds static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
28101da177e4SLinus Torvalds 				int length, int inout)
28111da177e4SLinus Torvalds {
28121da177e4SLinus Torvalds 	int len, pos, begin;
28131da177e4SLinus Torvalds 	int orig_length;
28141da177e4SLinus Torvalds 
28151da177e4SLinus Torvalds 	orig_length = length;
28161da177e4SLinus Torvalds 
28171da177e4SLinus Torvalds 	if (inout == 1) {
28181da177e4SLinus Torvalds 		char arr[16];
28191da177e4SLinus Torvalds 		int minLen = length > 15 ? 15 : length;
28201da177e4SLinus Torvalds 
28211da177e4SLinus Torvalds 		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
28221da177e4SLinus Torvalds 			return -EACCES;
28231da177e4SLinus Torvalds 		memcpy(arr, buffer, minLen);
28241da177e4SLinus Torvalds 		arr[minLen] = '\0';
28251da177e4SLinus Torvalds 		if (1 != sscanf(arr, "%d", &pos))
28261da177e4SLinus Torvalds 			return -EINVAL;
28271da177e4SLinus Torvalds 		scsi_debug_opts = pos;
28281da177e4SLinus Torvalds 		if (scsi_debug_every_nth != 0)
28291da177e4SLinus Torvalds                         scsi_debug_cmnd_count = 0;
28301da177e4SLinus Torvalds 		return length;
28311da177e4SLinus Torvalds 	}
28321da177e4SLinus Torvalds 	begin = 0;
28331da177e4SLinus Torvalds 	pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
28341da177e4SLinus Torvalds 	    "%s [%s]\n"
28351da177e4SLinus Torvalds 	    "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
28361da177e4SLinus Torvalds 	    "every_nth=%d(curr:%d)\n"
28371da177e4SLinus Torvalds 	    "delay=%d, max_luns=%d, scsi_level=%d\n"
28381da177e4SLinus Torvalds 	    "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
28391da177e4SLinus Torvalds 	    "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2840c6a44287SMartin K. Petersen 	    "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n",
28411da177e4SLinus Torvalds 	    SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
28421da177e4SLinus Torvalds 	    scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
28431da177e4SLinus Torvalds 	    scsi_debug_cmnd_count, scsi_debug_delay,
28441da177e4SLinus Torvalds 	    scsi_debug_max_luns, scsi_debug_scsi_level,
2845597136abSMartin K. Petersen 	    scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
2846597136abSMartin K. Petersen 	    sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
2847c6a44287SMartin K. Petersen 	    num_host_resets, dix_reads, dix_writes, dif_errors);
28481da177e4SLinus Torvalds 	if (pos < offset) {
28491da177e4SLinus Torvalds 		len = 0;
28501da177e4SLinus Torvalds 		begin = pos;
28511da177e4SLinus Torvalds 	}
28521da177e4SLinus Torvalds 	*start = buffer + (offset - begin);	/* Start of wanted data */
28531da177e4SLinus Torvalds 	len -= (offset - begin);
28541da177e4SLinus Torvalds 	if (len > length)
28551da177e4SLinus Torvalds 		len = length;
28561da177e4SLinus Torvalds 	return len;
28571da177e4SLinus Torvalds }
28581da177e4SLinus Torvalds 
28591da177e4SLinus Torvalds static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
28601da177e4SLinus Torvalds {
28611da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
28621da177e4SLinus Torvalds }
28631da177e4SLinus Torvalds 
28641da177e4SLinus Torvalds static ssize_t sdebug_delay_store(struct device_driver * ddp,
28651da177e4SLinus Torvalds 				  const char * buf, size_t count)
28661da177e4SLinus Torvalds {
28671da177e4SLinus Torvalds         int delay;
28681da177e4SLinus Torvalds 	char work[20];
28691da177e4SLinus Torvalds 
28701da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
28711da177e4SLinus Torvalds 		if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
28721da177e4SLinus Torvalds 			scsi_debug_delay = delay;
28731da177e4SLinus Torvalds 			return count;
28741da177e4SLinus Torvalds 		}
28751da177e4SLinus Torvalds 	}
28761da177e4SLinus Torvalds 	return -EINVAL;
28771da177e4SLinus Torvalds }
28781da177e4SLinus Torvalds DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
28791da177e4SLinus Torvalds 	    sdebug_delay_store);
28801da177e4SLinus Torvalds 
28811da177e4SLinus Torvalds static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
28821da177e4SLinus Torvalds {
28831da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
28841da177e4SLinus Torvalds }
28851da177e4SLinus Torvalds 
28861da177e4SLinus Torvalds static ssize_t sdebug_opts_store(struct device_driver * ddp,
28871da177e4SLinus Torvalds 				 const char * buf, size_t count)
28881da177e4SLinus Torvalds {
28891da177e4SLinus Torvalds         int opts;
28901da177e4SLinus Torvalds 	char work[20];
28911da177e4SLinus Torvalds 
28921da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
28931da177e4SLinus Torvalds 		if (0 == strnicmp(work,"0x", 2)) {
28941da177e4SLinus Torvalds 			if (1 == sscanf(&work[2], "%x", &opts))
28951da177e4SLinus Torvalds 				goto opts_done;
28961da177e4SLinus Torvalds 		} else {
28971da177e4SLinus Torvalds 			if (1 == sscanf(work, "%d", &opts))
28981da177e4SLinus Torvalds 				goto opts_done;
28991da177e4SLinus Torvalds 		}
29001da177e4SLinus Torvalds 	}
29011da177e4SLinus Torvalds 	return -EINVAL;
29021da177e4SLinus Torvalds opts_done:
29031da177e4SLinus Torvalds 	scsi_debug_opts = opts;
29041da177e4SLinus Torvalds 	scsi_debug_cmnd_count = 0;
29051da177e4SLinus Torvalds 	return count;
29061da177e4SLinus Torvalds }
29071da177e4SLinus Torvalds DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
29081da177e4SLinus Torvalds 	    sdebug_opts_store);
29091da177e4SLinus Torvalds 
29101da177e4SLinus Torvalds static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
29111da177e4SLinus Torvalds {
29121da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
29131da177e4SLinus Torvalds }
29141da177e4SLinus Torvalds static ssize_t sdebug_ptype_store(struct device_driver * ddp,
29151da177e4SLinus Torvalds 				  const char * buf, size_t count)
29161da177e4SLinus Torvalds {
29171da177e4SLinus Torvalds         int n;
29181da177e4SLinus Torvalds 
29191da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
29201da177e4SLinus Torvalds 		scsi_debug_ptype = n;
29211da177e4SLinus Torvalds 		return count;
29221da177e4SLinus Torvalds 	}
29231da177e4SLinus Torvalds 	return -EINVAL;
29241da177e4SLinus Torvalds }
29251da177e4SLinus Torvalds DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
29261da177e4SLinus Torvalds 
29271da177e4SLinus Torvalds static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
29281da177e4SLinus Torvalds {
29291da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
29301da177e4SLinus Torvalds }
29311da177e4SLinus Torvalds static ssize_t sdebug_dsense_store(struct device_driver * ddp,
29321da177e4SLinus Torvalds 				  const char * buf, size_t count)
29331da177e4SLinus Torvalds {
29341da177e4SLinus Torvalds         int n;
29351da177e4SLinus Torvalds 
29361da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
29371da177e4SLinus Torvalds 		scsi_debug_dsense = n;
29381da177e4SLinus Torvalds 		return count;
29391da177e4SLinus Torvalds 	}
29401da177e4SLinus Torvalds 	return -EINVAL;
29411da177e4SLinus Torvalds }
29421da177e4SLinus Torvalds DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
29431da177e4SLinus Torvalds 	    sdebug_dsense_store);
29441da177e4SLinus Torvalds 
294523183910SDouglas Gilbert static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
294623183910SDouglas Gilbert {
294723183910SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
294823183910SDouglas Gilbert }
294923183910SDouglas Gilbert static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
295023183910SDouglas Gilbert 				    const char * buf, size_t count)
295123183910SDouglas Gilbert {
295223183910SDouglas Gilbert         int n;
295323183910SDouglas Gilbert 
295423183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
295523183910SDouglas Gilbert 		scsi_debug_fake_rw = n;
295623183910SDouglas Gilbert 		return count;
295723183910SDouglas Gilbert 	}
295823183910SDouglas Gilbert 	return -EINVAL;
295923183910SDouglas Gilbert }
296023183910SDouglas Gilbert DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
296123183910SDouglas Gilbert 	    sdebug_fake_rw_store);
296223183910SDouglas Gilbert 
2963c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2964c65b1445SDouglas Gilbert {
2965c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2966c65b1445SDouglas Gilbert }
2967c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2968c65b1445SDouglas Gilbert 				     const char * buf, size_t count)
2969c65b1445SDouglas Gilbert {
2970c65b1445SDouglas Gilbert         int n;
2971c65b1445SDouglas Gilbert 
2972c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2973c65b1445SDouglas Gilbert 		scsi_debug_no_lun_0 = n;
2974c65b1445SDouglas Gilbert 		return count;
2975c65b1445SDouglas Gilbert 	}
2976c65b1445SDouglas Gilbert 	return -EINVAL;
2977c65b1445SDouglas Gilbert }
2978c65b1445SDouglas Gilbert DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2979c65b1445SDouglas Gilbert 	    sdebug_no_lun_0_store);
2980c65b1445SDouglas Gilbert 
29811da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
29821da177e4SLinus Torvalds {
29831da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
29841da177e4SLinus Torvalds }
29851da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
29861da177e4SLinus Torvalds 				     const char * buf, size_t count)
29871da177e4SLinus Torvalds {
29881da177e4SLinus Torvalds         int n;
29891da177e4SLinus Torvalds 
29901da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
29911da177e4SLinus Torvalds 		scsi_debug_num_tgts = n;
29921da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
29931da177e4SLinus Torvalds 		return count;
29941da177e4SLinus Torvalds 	}
29951da177e4SLinus Torvalds 	return -EINVAL;
29961da177e4SLinus Torvalds }
29971da177e4SLinus Torvalds DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
29981da177e4SLinus Torvalds 	    sdebug_num_tgts_store);
29991da177e4SLinus Torvalds 
30001da177e4SLinus Torvalds static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
30011da177e4SLinus Torvalds {
30021da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
30031da177e4SLinus Torvalds }
30041da177e4SLinus Torvalds DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
30051da177e4SLinus Torvalds 
30061da177e4SLinus Torvalds static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
30071da177e4SLinus Torvalds {
30081da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
30091da177e4SLinus Torvalds }
30101da177e4SLinus Torvalds DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
30111da177e4SLinus Torvalds 
30121da177e4SLinus Torvalds static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
30131da177e4SLinus Torvalds {
30141da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
30151da177e4SLinus Torvalds }
30161da177e4SLinus Torvalds static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
30171da177e4SLinus Torvalds 				      const char * buf, size_t count)
30181da177e4SLinus Torvalds {
30191da177e4SLinus Torvalds         int nth;
30201da177e4SLinus Torvalds 
30211da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
30221da177e4SLinus Torvalds 		scsi_debug_every_nth = nth;
30231da177e4SLinus Torvalds 		scsi_debug_cmnd_count = 0;
30241da177e4SLinus Torvalds 		return count;
30251da177e4SLinus Torvalds 	}
30261da177e4SLinus Torvalds 	return -EINVAL;
30271da177e4SLinus Torvalds }
30281da177e4SLinus Torvalds DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
30291da177e4SLinus Torvalds 	    sdebug_every_nth_store);
30301da177e4SLinus Torvalds 
30311da177e4SLinus Torvalds static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
30321da177e4SLinus Torvalds {
30331da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
30341da177e4SLinus Torvalds }
30351da177e4SLinus Torvalds static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
30361da177e4SLinus Torvalds 				     const char * buf, size_t count)
30371da177e4SLinus Torvalds {
30381da177e4SLinus Torvalds         int n;
30391da177e4SLinus Torvalds 
30401da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
30411da177e4SLinus Torvalds 		scsi_debug_max_luns = n;
30421da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
30431da177e4SLinus Torvalds 		return count;
30441da177e4SLinus Torvalds 	}
30451da177e4SLinus Torvalds 	return -EINVAL;
30461da177e4SLinus Torvalds }
30471da177e4SLinus Torvalds DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
30481da177e4SLinus Torvalds 	    sdebug_max_luns_store);
30491da177e4SLinus Torvalds 
305078d4e5a0SDouglas Gilbert static ssize_t sdebug_max_queue_show(struct device_driver * ddp, char * buf)
305178d4e5a0SDouglas Gilbert {
305278d4e5a0SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue);
305378d4e5a0SDouglas Gilbert }
305478d4e5a0SDouglas Gilbert static ssize_t sdebug_max_queue_store(struct device_driver * ddp,
305578d4e5a0SDouglas Gilbert 				      const char * buf, size_t count)
305678d4e5a0SDouglas Gilbert {
305778d4e5a0SDouglas Gilbert         int n;
305878d4e5a0SDouglas Gilbert 
305978d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
306078d4e5a0SDouglas Gilbert 	    (n <= SCSI_DEBUG_CANQUEUE)) {
306178d4e5a0SDouglas Gilbert 		scsi_debug_max_queue = n;
306278d4e5a0SDouglas Gilbert 		return count;
306378d4e5a0SDouglas Gilbert 	}
306478d4e5a0SDouglas Gilbert 	return -EINVAL;
306578d4e5a0SDouglas Gilbert }
306678d4e5a0SDouglas Gilbert DRIVER_ATTR(max_queue, S_IRUGO | S_IWUSR, sdebug_max_queue_show,
306778d4e5a0SDouglas Gilbert 	    sdebug_max_queue_store);
306878d4e5a0SDouglas Gilbert 
306978d4e5a0SDouglas Gilbert static ssize_t sdebug_no_uld_show(struct device_driver * ddp, char * buf)
307078d4e5a0SDouglas Gilbert {
307178d4e5a0SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld);
307278d4e5a0SDouglas Gilbert }
307378d4e5a0SDouglas Gilbert DRIVER_ATTR(no_uld, S_IRUGO, sdebug_no_uld_show, NULL);
307478d4e5a0SDouglas Gilbert 
30751da177e4SLinus Torvalds static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
30761da177e4SLinus Torvalds {
30771da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
30781da177e4SLinus Torvalds }
30791da177e4SLinus Torvalds DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
30801da177e4SLinus Torvalds 
3081c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
3082c65b1445SDouglas Gilbert {
3083c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
3084c65b1445SDouglas Gilbert }
3085c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
3086c65b1445SDouglas Gilbert 				       const char * buf, size_t count)
3087c65b1445SDouglas Gilbert {
3088c65b1445SDouglas Gilbert         int n;
3089c65b1445SDouglas Gilbert 
3090c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3091c65b1445SDouglas Gilbert 		scsi_debug_virtual_gb = n;
309228898873SFUJITA Tomonori 
309328898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
309428898873SFUJITA Tomonori 
3095c65b1445SDouglas Gilbert 		return count;
3096c65b1445SDouglas Gilbert 	}
3097c65b1445SDouglas Gilbert 	return -EINVAL;
3098c65b1445SDouglas Gilbert }
3099c65b1445SDouglas Gilbert DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
3100c65b1445SDouglas Gilbert 	    sdebug_virtual_gb_store);
3101c65b1445SDouglas Gilbert 
31021da177e4SLinus Torvalds static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
31031da177e4SLinus Torvalds {
31041da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
31051da177e4SLinus Torvalds }
31061da177e4SLinus Torvalds 
31071da177e4SLinus Torvalds static ssize_t sdebug_add_host_store(struct device_driver * ddp,
31081da177e4SLinus Torvalds 				     const char * buf, size_t count)
31091da177e4SLinus Torvalds {
31101da177e4SLinus Torvalds 	int delta_hosts;
31111da177e4SLinus Torvalds 
3112f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
31131da177e4SLinus Torvalds 		return -EINVAL;
31141da177e4SLinus Torvalds 	if (delta_hosts > 0) {
31151da177e4SLinus Torvalds 		do {
31161da177e4SLinus Torvalds 			sdebug_add_adapter();
31171da177e4SLinus Torvalds 		} while (--delta_hosts);
31181da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
31191da177e4SLinus Torvalds 		do {
31201da177e4SLinus Torvalds 			sdebug_remove_adapter();
31211da177e4SLinus Torvalds 		} while (++delta_hosts);
31221da177e4SLinus Torvalds 	}
31231da177e4SLinus Torvalds 	return count;
31241da177e4SLinus Torvalds }
31251da177e4SLinus Torvalds DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
31261da177e4SLinus Torvalds 	    sdebug_add_host_store);
31271da177e4SLinus Torvalds 
312823183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
312923183910SDouglas Gilbert 					  char * buf)
313023183910SDouglas Gilbert {
313123183910SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
313223183910SDouglas Gilbert }
313323183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
313423183910SDouglas Gilbert 					   const char * buf, size_t count)
313523183910SDouglas Gilbert {
313623183910SDouglas Gilbert 	int n;
313723183910SDouglas Gilbert 
313823183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
313923183910SDouglas Gilbert 		scsi_debug_vpd_use_hostno = n;
314023183910SDouglas Gilbert 		return count;
314123183910SDouglas Gilbert 	}
314223183910SDouglas Gilbert 	return -EINVAL;
314323183910SDouglas Gilbert }
314423183910SDouglas Gilbert DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
314523183910SDouglas Gilbert 	    sdebug_vpd_use_hostno_store);
314623183910SDouglas Gilbert 
3147597136abSMartin K. Petersen static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf)
3148597136abSMartin K. Petersen {
3149597136abSMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
3150597136abSMartin K. Petersen }
3151597136abSMartin K. Petersen DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL);
3152597136abSMartin K. Petersen 
3153c6a44287SMartin K. Petersen static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf)
3154c6a44287SMartin K. Petersen {
3155c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
3156c6a44287SMartin K. Petersen }
3157c6a44287SMartin K. Petersen DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL);
3158c6a44287SMartin K. Petersen 
3159c6a44287SMartin K. Petersen static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf)
3160c6a44287SMartin K. Petersen {
3161c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
3162c6a44287SMartin K. Petersen }
3163c6a44287SMartin K. Petersen DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL);
3164c6a44287SMartin K. Petersen 
3165c6a44287SMartin K. Petersen static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf)
3166c6a44287SMartin K. Petersen {
3167c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard);
3168c6a44287SMartin K. Petersen }
3169c6a44287SMartin K. Petersen DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL);
3170c6a44287SMartin K. Petersen 
3171c6a44287SMartin K. Petersen static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf)
3172c6a44287SMartin K. Petersen {
3173c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
3174c6a44287SMartin K. Petersen }
3175c6a44287SMartin K. Petersen DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL);
3176c6a44287SMartin K. Petersen 
317744d92694SMartin K. Petersen static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf)
317844d92694SMartin K. Petersen {
317944d92694SMartin K. Petersen 	ssize_t count;
318044d92694SMartin K. Petersen 
31815b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
318244d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
318344d92694SMartin K. Petersen 				 sdebug_store_sectors);
318444d92694SMartin K. Petersen 
318544d92694SMartin K. Petersen 	count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
318644d92694SMartin K. Petersen 
318744d92694SMartin K. Petersen 	buf[count++] = '\n';
318844d92694SMartin K. Petersen 	buf[count++] = 0;
318944d92694SMartin K. Petersen 
319044d92694SMartin K. Petersen 	return count;
319144d92694SMartin K. Petersen }
319244d92694SMartin K. Petersen DRIVER_ATTR(map, S_IRUGO, sdebug_map_show, NULL);
319344d92694SMartin K. Petersen 
3194c6a44287SMartin K. Petersen 
319523183910SDouglas Gilbert /* Note: The following function creates attribute files in the
319623183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
319723183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
319823183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
319923183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
320023183910SDouglas Gilbert  */
32016ecaff7fSRandy Dunlap static int do_create_driverfs_files(void)
32021da177e4SLinus Torvalds {
32036ecaff7fSRandy Dunlap 	int ret;
32046ecaff7fSRandy Dunlap 
32056ecaff7fSRandy Dunlap 	ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
32066ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
32076ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
32086ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
32096ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
321023183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
32116ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
321278d4e5a0SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_queue);
321323183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
321478d4e5a0SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_uld);
32156ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
321623183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
32176ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
32186ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
32196ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
322023183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
322123183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
3222597136abSMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
3223c6a44287SMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix);
3224c6a44287SMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif);
3225c6a44287SMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard);
3226c6a44287SMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato);
322744d92694SMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_map);
32286ecaff7fSRandy Dunlap 	return ret;
32291da177e4SLinus Torvalds }
32301da177e4SLinus Torvalds 
32311da177e4SLinus Torvalds static void do_remove_driverfs_files(void)
32321da177e4SLinus Torvalds {
323344d92694SMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_map);
3234c6a44287SMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato);
3235c6a44287SMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard);
3236c6a44287SMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif);
3237c6a44287SMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix);
3238597136abSMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
323923183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
324023183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
32411da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
32421da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
32431da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
32441da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
324523183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
324678d4e5a0SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_uld);
324723183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
324878d4e5a0SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_queue);
32491da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
325023183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
32511da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
32521da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
32531da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
32541da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
32551da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
32561da177e4SLinus Torvalds }
32571da177e4SLinus Torvalds 
32589b906779SNicholas Bellinger struct device *pseudo_primary;
32598dea0d02SFUJITA Tomonori 
32601da177e4SLinus Torvalds static int __init scsi_debug_init(void)
32611da177e4SLinus Torvalds {
32625f2578e5SFUJITA Tomonori 	unsigned long sz;
32631da177e4SLinus Torvalds 	int host_to_add;
32641da177e4SLinus Torvalds 	int k;
32656ecaff7fSRandy Dunlap 	int ret;
32661da177e4SLinus Torvalds 
3267597136abSMartin K. Petersen 	switch (scsi_debug_sector_size) {
3268597136abSMartin K. Petersen 	case  512:
3269597136abSMartin K. Petersen 	case 1024:
3270597136abSMartin K. Petersen 	case 2048:
3271597136abSMartin K. Petersen 	case 4096:
3272597136abSMartin K. Petersen 		break;
3273597136abSMartin K. Petersen 	default:
3274c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n",
3275597136abSMartin K. Petersen 		       scsi_debug_sector_size);
3276597136abSMartin K. Petersen 		return -EINVAL;
3277597136abSMartin K. Petersen 	}
3278597136abSMartin K. Petersen 
3279c6a44287SMartin K. Petersen 	switch (scsi_debug_dif) {
3280c6a44287SMartin K. Petersen 
3281c6a44287SMartin K. Petersen 	case SD_DIF_TYPE0_PROTECTION:
3282c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
3283395cef03SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
3284c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
3285c6a44287SMartin K. Petersen 		break;
3286c6a44287SMartin K. Petersen 
3287c6a44287SMartin K. Petersen 	default:
3288395cef03SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n");
3289c6a44287SMartin K. Petersen 		return -EINVAL;
3290c6a44287SMartin K. Petersen 	}
3291c6a44287SMartin K. Petersen 
3292c6a44287SMartin K. Petersen 	if (scsi_debug_guard > 1) {
3293c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n");
3294c6a44287SMartin K. Petersen 		return -EINVAL;
3295c6a44287SMartin K. Petersen 	}
3296c6a44287SMartin K. Petersen 
3297c6a44287SMartin K. Petersen 	if (scsi_debug_ato > 1) {
3298c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n");
3299c6a44287SMartin K. Petersen 		return -EINVAL;
3300c6a44287SMartin K. Petersen 	}
3301c6a44287SMartin K. Petersen 
3302ea61fca5SMartin K. Petersen 	if (scsi_debug_physblk_exp > 15) {
3303ea61fca5SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n",
3304ea61fca5SMartin K. Petersen 		       scsi_debug_physblk_exp);
3305ea61fca5SMartin K. Petersen 		return -EINVAL;
3306ea61fca5SMartin K. Petersen 	}
3307ea61fca5SMartin K. Petersen 
3308ea61fca5SMartin K. Petersen 	if (scsi_debug_lowest_aligned > 0x3fff) {
3309ea61fca5SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n",
3310ea61fca5SMartin K. Petersen 		       scsi_debug_lowest_aligned);
3311ea61fca5SMartin K. Petersen 		return -EINVAL;
3312ea61fca5SMartin K. Petersen 	}
3313ea61fca5SMartin K. Petersen 
33141da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb < 1)
33151da177e4SLinus Torvalds 		scsi_debug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
33165f2578e5SFUJITA Tomonori 	sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
3317597136abSMartin K. Petersen 	sdebug_store_sectors = sz / scsi_debug_sector_size;
331828898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
33191da177e4SLinus Torvalds 
33201da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
33211da177e4SLinus Torvalds 	sdebug_heads = 8;
33221da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
33231da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb >= 16)
33241da177e4SLinus Torvalds 		sdebug_heads = 32;
33251da177e4SLinus Torvalds 	else if (scsi_debug_dev_size_mb >= 256)
33261da177e4SLinus Torvalds 		sdebug_heads = 64;
33271da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
33281da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
33291da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
33301da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
33311da177e4SLinus Torvalds 		sdebug_heads = 255;
33321da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
33331da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
33341da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
33351da177e4SLinus Torvalds 	}
33361da177e4SLinus Torvalds 
33371da177e4SLinus Torvalds 	fake_storep = vmalloc(sz);
33381da177e4SLinus Torvalds 	if (NULL == fake_storep) {
33391da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
33401da177e4SLinus Torvalds 		return -ENOMEM;
33411da177e4SLinus Torvalds 	}
33421da177e4SLinus Torvalds 	memset(fake_storep, 0, sz);
33431da177e4SLinus Torvalds 	if (scsi_debug_num_parts > 0)
3344f58b0efbSFUJITA Tomonori 		sdebug_build_parts(fake_storep, sz);
33451da177e4SLinus Torvalds 
3346c6a44287SMartin K. Petersen 	if (scsi_debug_dif) {
3347c6a44287SMartin K. Petersen 		int dif_size;
3348c6a44287SMartin K. Petersen 
3349c6a44287SMartin K. Petersen 		dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
3350c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
3351c6a44287SMartin K. Petersen 
3352c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n",
3353c6a44287SMartin K. Petersen 		       dif_size, dif_storep);
3354c6a44287SMartin K. Petersen 
3355c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
3356c6a44287SMartin K. Petersen 			printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n");
3357c6a44287SMartin K. Petersen 			ret = -ENOMEM;
3358c6a44287SMartin K. Petersen 			goto free_vm;
3359c6a44287SMartin K. Petersen 		}
3360c6a44287SMartin K. Petersen 
3361c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
3362c6a44287SMartin K. Petersen 	}
3363c6a44287SMartin K. Petersen 
33645b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
33655b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
336644d92694SMartin K. Petersen 		unsigned int map_bytes;
336744d92694SMartin K. Petersen 
33686014759cSMartin K. Petersen 		scsi_debug_unmap_max_blocks =
33696014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU);
33706014759cSMartin K. Petersen 
33716014759cSMartin K. Petersen 		scsi_debug_unmap_max_desc =
33726014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_max_desc, 0U, 256U);
33736014759cSMartin K. Petersen 
33746014759cSMartin K. Petersen 		scsi_debug_unmap_granularity =
33756014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU);
33766014759cSMartin K. Petersen 
33776014759cSMartin K. Petersen 		if (scsi_debug_unmap_alignment &&
33786014759cSMartin K. Petersen 		    scsi_debug_unmap_granularity < scsi_debug_unmap_alignment) {
337944d92694SMartin K. Petersen 			printk(KERN_ERR
338044d92694SMartin K. Petersen 			       "%s: ERR: unmap_granularity < unmap_alignment\n",
338144d92694SMartin K. Petersen 			       __func__);
338244d92694SMartin K. Petersen 			return -EINVAL;
338344d92694SMartin K. Petersen 		}
338444d92694SMartin K. Petersen 
338544d92694SMartin K. Petersen 		map_size = (sdebug_store_sectors / scsi_debug_unmap_granularity);
338644d92694SMartin K. Petersen 		map_bytes = map_size >> 3;
338744d92694SMartin K. Petersen 		map_storep = vmalloc(map_bytes);
338844d92694SMartin K. Petersen 
338944d92694SMartin K. Petersen 		printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n",
339044d92694SMartin K. Petersen 		       map_size);
339144d92694SMartin K. Petersen 
339244d92694SMartin K. Petersen 		if (map_storep == NULL) {
339344d92694SMartin K. Petersen 			printk(KERN_ERR "scsi_debug_init: out of mem. (MAP)\n");
339444d92694SMartin K. Petersen 			ret = -ENOMEM;
339544d92694SMartin K. Petersen 			goto free_vm;
339644d92694SMartin K. Petersen 		}
339744d92694SMartin K. Petersen 
339844d92694SMartin K. Petersen 		memset(map_storep, 0x0, map_bytes);
339944d92694SMartin K. Petersen 
340044d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
340144d92694SMartin K. Petersen 		if (scsi_debug_num_parts)
340244d92694SMartin K. Petersen 			map_region(0, 2);
340344d92694SMartin K. Petersen 	}
340444d92694SMartin K. Petersen 
34059b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
34069b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
34079b906779SNicholas Bellinger 		printk(KERN_WARNING "scsi_debug: root_device_register() error\n");
34089b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
34096ecaff7fSRandy Dunlap 		goto free_vm;
34106ecaff7fSRandy Dunlap 	}
34116ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
34126ecaff7fSRandy Dunlap 	if (ret < 0) {
34136ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
34146ecaff7fSRandy Dunlap 			ret);
34156ecaff7fSRandy Dunlap 		goto dev_unreg;
34166ecaff7fSRandy Dunlap 	}
34176ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
34186ecaff7fSRandy Dunlap 	if (ret < 0) {
34196ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
34206ecaff7fSRandy Dunlap 			ret);
34216ecaff7fSRandy Dunlap 		goto bus_unreg;
34226ecaff7fSRandy Dunlap 	}
34236ecaff7fSRandy Dunlap 	ret = do_create_driverfs_files();
34246ecaff7fSRandy Dunlap 	if (ret < 0) {
34256ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
34266ecaff7fSRandy Dunlap 			ret);
34276ecaff7fSRandy Dunlap 		goto del_files;
34286ecaff7fSRandy Dunlap 	}
34291da177e4SLinus Torvalds 
34306ecaff7fSRandy Dunlap 	init_all_queued();
34311da177e4SLinus Torvalds 
34321da177e4SLinus Torvalds 	host_to_add = scsi_debug_add_host;
34331da177e4SLinus Torvalds         scsi_debug_add_host = 0;
34341da177e4SLinus Torvalds 
34351da177e4SLinus Torvalds         for (k = 0; k < host_to_add; k++) {
34361da177e4SLinus Torvalds                 if (sdebug_add_adapter()) {
34371da177e4SLinus Torvalds                         printk(KERN_ERR "scsi_debug_init: "
34381da177e4SLinus Torvalds                                "sdebug_add_adapter failed k=%d\n", k);
34391da177e4SLinus Torvalds                         break;
34401da177e4SLinus Torvalds                 }
34411da177e4SLinus Torvalds         }
34421da177e4SLinus Torvalds 
34431da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
34441da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
34451da177e4SLinus Torvalds 		       scsi_debug_add_host);
34461da177e4SLinus Torvalds 	}
34471da177e4SLinus Torvalds 	return 0;
34486ecaff7fSRandy Dunlap 
34496ecaff7fSRandy Dunlap del_files:
34506ecaff7fSRandy Dunlap 	do_remove_driverfs_files();
34516ecaff7fSRandy Dunlap 	driver_unregister(&sdebug_driverfs_driver);
34526ecaff7fSRandy Dunlap bus_unreg:
34536ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
34546ecaff7fSRandy Dunlap dev_unreg:
34559b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
34566ecaff7fSRandy Dunlap free_vm:
345744d92694SMartin K. Petersen 	if (map_storep)
345844d92694SMartin K. Petersen 		vfree(map_storep);
3459c6a44287SMartin K. Petersen 	if (dif_storep)
3460c6a44287SMartin K. Petersen 		vfree(dif_storep);
34616ecaff7fSRandy Dunlap 	vfree(fake_storep);
34626ecaff7fSRandy Dunlap 
34636ecaff7fSRandy Dunlap 	return ret;
34641da177e4SLinus Torvalds }
34651da177e4SLinus Torvalds 
34661da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
34671da177e4SLinus Torvalds {
34681da177e4SLinus Torvalds 	int k = scsi_debug_add_host;
34691da177e4SLinus Torvalds 
34701da177e4SLinus Torvalds 	stop_all_queued();
34711da177e4SLinus Torvalds 	for (; k; k--)
34721da177e4SLinus Torvalds 		sdebug_remove_adapter();
34731da177e4SLinus Torvalds 	do_remove_driverfs_files();
34741da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
34751da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
34769b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
34771da177e4SLinus Torvalds 
3478c6a44287SMartin K. Petersen 	if (dif_storep)
3479c6a44287SMartin K. Petersen 		vfree(dif_storep);
3480c6a44287SMartin K. Petersen 
34811da177e4SLinus Torvalds 	vfree(fake_storep);
34821da177e4SLinus Torvalds }
34831da177e4SLinus Torvalds 
34841da177e4SLinus Torvalds device_initcall(scsi_debug_init);
34851da177e4SLinus Torvalds module_exit(scsi_debug_exit);
34861da177e4SLinus Torvalds 
34871da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev)
34881da177e4SLinus Torvalds {
34891da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
34901da177e4SLinus Torvalds 
34911da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
34921da177e4SLinus Torvalds         kfree(sdbg_host);
34931da177e4SLinus Torvalds }
34941da177e4SLinus Torvalds 
34951da177e4SLinus Torvalds static int sdebug_add_adapter(void)
34961da177e4SLinus Torvalds {
34971da177e4SLinus Torvalds 	int k, devs_per_host;
34981da177e4SLinus Torvalds         int error = 0;
34991da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
35008b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
35011da177e4SLinus Torvalds 
350224669f75SJes Sorensen         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
35031da177e4SLinus Torvalds         if (NULL == sdbg_host) {
35041da177e4SLinus Torvalds                 printk(KERN_ERR "%s: out of memory at line %d\n",
3505cadbd4a5SHarvey Harrison                        __func__, __LINE__);
35061da177e4SLinus Torvalds                 return -ENOMEM;
35071da177e4SLinus Torvalds         }
35081da177e4SLinus Torvalds 
35091da177e4SLinus Torvalds         INIT_LIST_HEAD(&sdbg_host->dev_info_list);
35101da177e4SLinus Torvalds 
35111da177e4SLinus Torvalds 	devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
35121da177e4SLinus Torvalds         for (k = 0; k < devs_per_host; k++) {
35135cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
35145cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
35151da177e4SLinus Torvalds                         printk(KERN_ERR "%s: out of memory at line %d\n",
3516cadbd4a5SHarvey Harrison                                __func__, __LINE__);
35171da177e4SLinus Torvalds                         error = -ENOMEM;
35181da177e4SLinus Torvalds 			goto clean;
35191da177e4SLinus Torvalds                 }
35201da177e4SLinus Torvalds         }
35211da177e4SLinus Torvalds 
35221da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
35231da177e4SLinus Torvalds         list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
35241da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
35251da177e4SLinus Torvalds 
35261da177e4SLinus Torvalds         sdbg_host->dev.bus = &pseudo_lld_bus;
35279b906779SNicholas Bellinger         sdbg_host->dev.parent = pseudo_primary;
35281da177e4SLinus Torvalds         sdbg_host->dev.release = &sdebug_release_adapter;
352971610f55SKay Sievers         dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
35301da177e4SLinus Torvalds 
35311da177e4SLinus Torvalds         error = device_register(&sdbg_host->dev);
35321da177e4SLinus Torvalds 
35331da177e4SLinus Torvalds         if (error)
35341da177e4SLinus Torvalds 		goto clean;
35351da177e4SLinus Torvalds 
35361da177e4SLinus Torvalds 	++scsi_debug_add_host;
35371da177e4SLinus Torvalds         return error;
35381da177e4SLinus Torvalds 
35391da177e4SLinus Torvalds clean:
35408b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
35418b40228fSFUJITA Tomonori 				 dev_list) {
35421da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
35431da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
35441da177e4SLinus Torvalds 	}
35451da177e4SLinus Torvalds 
35461da177e4SLinus Torvalds 	kfree(sdbg_host);
35471da177e4SLinus Torvalds         return error;
35481da177e4SLinus Torvalds }
35491da177e4SLinus Torvalds 
35501da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
35511da177e4SLinus Torvalds {
35521da177e4SLinus Torvalds         struct sdebug_host_info * sdbg_host = NULL;
35531da177e4SLinus Torvalds 
35541da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
35551da177e4SLinus Torvalds         if (!list_empty(&sdebug_host_list)) {
35561da177e4SLinus Torvalds                 sdbg_host = list_entry(sdebug_host_list.prev,
35571da177e4SLinus Torvalds                                        struct sdebug_host_info, host_list);
35581da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
35591da177e4SLinus Torvalds 	}
35601da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
35611da177e4SLinus Torvalds 
35621da177e4SLinus Torvalds 	if (!sdbg_host)
35631da177e4SLinus Torvalds 		return;
35641da177e4SLinus Torvalds 
35651da177e4SLinus Torvalds         device_unregister(&sdbg_host->dev);
35661da177e4SLinus Torvalds         --scsi_debug_add_host;
35671da177e4SLinus Torvalds }
35681da177e4SLinus Torvalds 
3569639db475SFUJITA Tomonori static
3570f281233dSJeff Garzik int scsi_debug_queuecommand_lck(struct scsi_cmnd *SCpnt, done_funct_t done)
3571639db475SFUJITA Tomonori {
3572639db475SFUJITA Tomonori 	unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
3573639db475SFUJITA Tomonori 	int len, k;
3574639db475SFUJITA Tomonori 	unsigned int num;
3575639db475SFUJITA Tomonori 	unsigned long long lba;
3576395cef03SMartin K. Petersen 	u32 ei_lba;
3577639db475SFUJITA Tomonori 	int errsts = 0;
3578639db475SFUJITA Tomonori 	int target = SCpnt->device->id;
3579639db475SFUJITA Tomonori 	struct sdebug_dev_info *devip = NULL;
3580639db475SFUJITA Tomonori 	int inj_recovered = 0;
3581639db475SFUJITA Tomonori 	int inj_transport = 0;
3582c6a44287SMartin K. Petersen 	int inj_dif = 0;
3583c6a44287SMartin K. Petersen 	int inj_dix = 0;
3584639db475SFUJITA Tomonori 	int delay_override = 0;
358544d92694SMartin K. Petersen 	int unmap = 0;
3586639db475SFUJITA Tomonori 
3587639db475SFUJITA Tomonori 	scsi_set_resid(SCpnt, 0);
3588639db475SFUJITA Tomonori 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
3589639db475SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: cmd ");
3590639db475SFUJITA Tomonori 		for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
3591639db475SFUJITA Tomonori 			printk("%02x ", (int)cmd[k]);
3592639db475SFUJITA Tomonori 		printk("\n");
3593639db475SFUJITA Tomonori 	}
3594639db475SFUJITA Tomonori 
3595639db475SFUJITA Tomonori 	if (target == SCpnt->device->host->hostt->this_id) {
3596639db475SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: initiator's id used as "
3597639db475SFUJITA Tomonori 		       "target!\n");
3598639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
3599639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
3600639db475SFUJITA Tomonori 	}
3601639db475SFUJITA Tomonori 
3602639db475SFUJITA Tomonori 	if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
3603639db475SFUJITA Tomonori 	    (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
3604639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
3605639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
3606639db475SFUJITA Tomonori 	devip = devInfoReg(SCpnt->device);
3607639db475SFUJITA Tomonori 	if (NULL == devip)
3608639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
3609639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
3610639db475SFUJITA Tomonori 
3611639db475SFUJITA Tomonori 	if ((scsi_debug_every_nth != 0) &&
3612639db475SFUJITA Tomonori 	    (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
3613639db475SFUJITA Tomonori 		scsi_debug_cmnd_count = 0;
3614639db475SFUJITA Tomonori 		if (scsi_debug_every_nth < -1)
3615639db475SFUJITA Tomonori 			scsi_debug_every_nth = -1;
3616639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
3617639db475SFUJITA Tomonori 			return 0; /* ignore command causing timeout */
3618639db475SFUJITA Tomonori 		else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
3619639db475SFUJITA Tomonori 			inj_recovered = 1; /* to reads and writes below */
3620639db475SFUJITA Tomonori 		else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
3621639db475SFUJITA Tomonori 			inj_transport = 1; /* to reads and writes below */
3622c6a44287SMartin K. Petersen 		else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
3623c6a44287SMartin K. Petersen 			inj_dif = 1; /* to reads and writes below */
3624c6a44287SMartin K. Petersen 		else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
3625c6a44287SMartin K. Petersen 			inj_dix = 1; /* to reads and writes below */
3626639db475SFUJITA Tomonori 	}
3627639db475SFUJITA Tomonori 
3628639db475SFUJITA Tomonori 	if (devip->wlun) {
3629639db475SFUJITA Tomonori 		switch (*cmd) {
3630639db475SFUJITA Tomonori 		case INQUIRY:
3631639db475SFUJITA Tomonori 		case REQUEST_SENSE:
3632639db475SFUJITA Tomonori 		case TEST_UNIT_READY:
3633639db475SFUJITA Tomonori 		case REPORT_LUNS:
3634639db475SFUJITA Tomonori 			break;  /* only allowable wlun commands */
3635639db475SFUJITA Tomonori 		default:
3636639db475SFUJITA Tomonori 			if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3637639db475SFUJITA Tomonori 				printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
3638639db475SFUJITA Tomonori 				       "not supported for wlun\n", *cmd);
3639639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3640639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
3641639db475SFUJITA Tomonori 			errsts = check_condition_result;
3642639db475SFUJITA Tomonori 			return schedule_resp(SCpnt, devip, done, errsts,
3643639db475SFUJITA Tomonori 					     0);
3644639db475SFUJITA Tomonori 		}
3645639db475SFUJITA Tomonori 	}
3646639db475SFUJITA Tomonori 
3647639db475SFUJITA Tomonori 	switch (*cmd) {
3648639db475SFUJITA Tomonori 	case INQUIRY:     /* mandatory, ignore unit attention */
3649639db475SFUJITA Tomonori 		delay_override = 1;
3650639db475SFUJITA Tomonori 		errsts = resp_inquiry(SCpnt, target, devip);
3651639db475SFUJITA Tomonori 		break;
3652639db475SFUJITA Tomonori 	case REQUEST_SENSE:	/* mandatory, ignore unit attention */
3653639db475SFUJITA Tomonori 		delay_override = 1;
3654639db475SFUJITA Tomonori 		errsts = resp_requests(SCpnt, devip);
3655639db475SFUJITA Tomonori 		break;
3656639db475SFUJITA Tomonori 	case REZERO_UNIT:	/* actually this is REWIND for SSC */
3657639db475SFUJITA Tomonori 	case START_STOP:
3658639db475SFUJITA Tomonori 		errsts = resp_start_stop(SCpnt, devip);
3659639db475SFUJITA Tomonori 		break;
3660639db475SFUJITA Tomonori 	case ALLOW_MEDIUM_REMOVAL:
3661639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3662639db475SFUJITA Tomonori 		if (errsts)
3663639db475SFUJITA Tomonori 			break;
3664639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3665639db475SFUJITA Tomonori 			printk(KERN_INFO "scsi_debug: Medium removal %s\n",
3666639db475SFUJITA Tomonori 			       cmd[4] ? "inhibited" : "enabled");
3667639db475SFUJITA Tomonori 		break;
3668639db475SFUJITA Tomonori 	case SEND_DIAGNOSTIC:     /* mandatory */
3669639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3670639db475SFUJITA Tomonori 		break;
3671639db475SFUJITA Tomonori 	case TEST_UNIT_READY:     /* mandatory */
3672639db475SFUJITA Tomonori 		delay_override = 1;
3673639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3674639db475SFUJITA Tomonori 		break;
3675639db475SFUJITA Tomonori 	case RESERVE:
3676639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3677639db475SFUJITA Tomonori 		break;
3678639db475SFUJITA Tomonori 	case RESERVE_10:
3679639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3680639db475SFUJITA Tomonori 		break;
3681639db475SFUJITA Tomonori 	case RELEASE:
3682639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3683639db475SFUJITA Tomonori 		break;
3684639db475SFUJITA Tomonori 	case RELEASE_10:
3685639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3686639db475SFUJITA Tomonori 		break;
3687639db475SFUJITA Tomonori 	case READ_CAPACITY:
3688639db475SFUJITA Tomonori 		errsts = resp_readcap(SCpnt, devip);
3689639db475SFUJITA Tomonori 		break;
3690639db475SFUJITA Tomonori 	case SERVICE_ACTION_IN:
369144d92694SMartin K. Petersen 		if (cmd[1] == SAI_READ_CAPACITY_16)
369244d92694SMartin K. Petersen 			errsts = resp_readcap16(SCpnt, devip);
369344d92694SMartin K. Petersen 		else if (cmd[1] == SAI_GET_LBA_STATUS) {
369444d92694SMartin K. Petersen 
36955b94e232SMartin K. Petersen 			if (scsi_debug_lbp() == 0) {
369644d92694SMartin K. Petersen 				mk_sense_buffer(devip, ILLEGAL_REQUEST,
369744d92694SMartin K. Petersen 						INVALID_COMMAND_OPCODE, 0);
369844d92694SMartin K. Petersen 				errsts = check_condition_result;
369944d92694SMartin K. Petersen 			} else
370044d92694SMartin K. Petersen 				errsts = resp_get_lba_status(SCpnt, devip);
370144d92694SMartin K. Petersen 		} else {
3702639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3703639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
3704639db475SFUJITA Tomonori 			errsts = check_condition_result;
3705639db475SFUJITA Tomonori 		}
3706639db475SFUJITA Tomonori 		break;
3707639db475SFUJITA Tomonori 	case MAINTENANCE_IN:
3708639db475SFUJITA Tomonori 		if (MI_REPORT_TARGET_PGS != cmd[1]) {
3709639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3710639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
3711639db475SFUJITA Tomonori 			errsts = check_condition_result;
3712639db475SFUJITA Tomonori 			break;
3713639db475SFUJITA Tomonori 		}
3714639db475SFUJITA Tomonori 		errsts = resp_report_tgtpgs(SCpnt, devip);
3715639db475SFUJITA Tomonori 		break;
3716639db475SFUJITA Tomonori 	case READ_16:
3717639db475SFUJITA Tomonori 	case READ_12:
3718639db475SFUJITA Tomonori 	case READ_10:
3719395cef03SMartin K. Petersen 		/* READ{10,12,16} and DIF Type 2 are natural enemies */
3720395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3721395cef03SMartin K. Petersen 		    cmd[1] & 0xe0) {
3722395cef03SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3723395cef03SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
3724395cef03SMartin K. Petersen 			errsts = check_condition_result;
3725395cef03SMartin K. Petersen 			break;
3726395cef03SMartin K. Petersen 		}
3727395cef03SMartin K. Petersen 
3728395cef03SMartin K. Petersen 		if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3729395cef03SMartin K. Petersen 		     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3730395cef03SMartin K. Petersen 		    (cmd[1] & 0xe0) == 0)
3731395cef03SMartin K. Petersen 			printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3732395cef03SMartin K. Petersen 
3733395cef03SMartin K. Petersen 		/* fall through */
3734639db475SFUJITA Tomonori 	case READ_6:
3735395cef03SMartin K. Petersen read:
3736639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3737639db475SFUJITA Tomonori 		if (errsts)
3738639db475SFUJITA Tomonori 			break;
3739639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
3740639db475SFUJITA Tomonori 			break;
3741395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3742395cef03SMartin K. Petersen 		errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
3743639db475SFUJITA Tomonori 		if (inj_recovered && (0 == errsts)) {
3744639db475SFUJITA Tomonori 			mk_sense_buffer(devip, RECOVERED_ERROR,
3745639db475SFUJITA Tomonori 					THRESHOLD_EXCEEDED, 0);
3746639db475SFUJITA Tomonori 			errsts = check_condition_result;
3747639db475SFUJITA Tomonori 		} else if (inj_transport && (0 == errsts)) {
3748639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ABORTED_COMMAND,
3749639db475SFUJITA Tomonori 					TRANSPORT_PROBLEM, ACK_NAK_TO);
3750639db475SFUJITA Tomonori 			errsts = check_condition_result;
3751c6a44287SMartin K. Petersen 		} else if (inj_dif && (0 == errsts)) {
3752c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3753c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3754c6a44287SMartin K. Petersen 		} else if (inj_dix && (0 == errsts)) {
3755c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3756c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3757639db475SFUJITA Tomonori 		}
3758639db475SFUJITA Tomonori 		break;
3759639db475SFUJITA Tomonori 	case REPORT_LUNS:	/* mandatory, ignore unit attention */
3760639db475SFUJITA Tomonori 		delay_override = 1;
3761639db475SFUJITA Tomonori 		errsts = resp_report_luns(SCpnt, devip);
3762639db475SFUJITA Tomonori 		break;
3763639db475SFUJITA Tomonori 	case VERIFY:		/* 10 byte SBC-2 command */
3764639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3765639db475SFUJITA Tomonori 		break;
3766639db475SFUJITA Tomonori 	case WRITE_16:
3767639db475SFUJITA Tomonori 	case WRITE_12:
3768639db475SFUJITA Tomonori 	case WRITE_10:
3769395cef03SMartin K. Petersen 		/* WRITE{10,12,16} and DIF Type 2 are natural enemies */
3770395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3771395cef03SMartin K. Petersen 		    cmd[1] & 0xe0) {
3772395cef03SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3773395cef03SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
3774395cef03SMartin K. Petersen 			errsts = check_condition_result;
3775395cef03SMartin K. Petersen 			break;
3776395cef03SMartin K. Petersen 		}
3777395cef03SMartin K. Petersen 
3778395cef03SMartin K. Petersen 		if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3779395cef03SMartin K. Petersen 		     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3780395cef03SMartin K. Petersen 		    (cmd[1] & 0xe0) == 0)
3781395cef03SMartin K. Petersen 			printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3782395cef03SMartin K. Petersen 
3783395cef03SMartin K. Petersen 		/* fall through */
3784639db475SFUJITA Tomonori 	case WRITE_6:
3785395cef03SMartin K. Petersen write:
3786639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3787639db475SFUJITA Tomonori 		if (errsts)
3788639db475SFUJITA Tomonori 			break;
3789639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
3790639db475SFUJITA Tomonori 			break;
3791395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3792395cef03SMartin K. Petersen 		errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
3793639db475SFUJITA Tomonori 		if (inj_recovered && (0 == errsts)) {
3794639db475SFUJITA Tomonori 			mk_sense_buffer(devip, RECOVERED_ERROR,
3795639db475SFUJITA Tomonori 					THRESHOLD_EXCEEDED, 0);
3796639db475SFUJITA Tomonori 			errsts = check_condition_result;
3797c6a44287SMartin K. Petersen 		} else if (inj_dif && (0 == errsts)) {
3798c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3799c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3800c6a44287SMartin K. Petersen 		} else if (inj_dix && (0 == errsts)) {
3801c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3802c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3803639db475SFUJITA Tomonori 		}
3804639db475SFUJITA Tomonori 		break;
380544d92694SMartin K. Petersen 	case WRITE_SAME_16:
38065b94e232SMartin K. Petersen 	case WRITE_SAME:
38076014759cSMartin K. Petersen 		if (cmd[1] & 0x8) {
38085b94e232SMartin K. Petersen 			if ((*cmd == WRITE_SAME_16 && scsi_debug_lbpws == 0) ||
38095b94e232SMartin K. Petersen 			    (*cmd == WRITE_SAME && scsi_debug_lbpws10 == 0)) {
38106014759cSMartin K. Petersen 				mk_sense_buffer(devip, ILLEGAL_REQUEST,
38116014759cSMartin K. Petersen 						INVALID_FIELD_IN_CDB, 0);
38126014759cSMartin K. Petersen 				errsts = check_condition_result;
38136014759cSMartin K. Petersen 			} else
381444d92694SMartin K. Petersen 				unmap = 1;
38156014759cSMartin K. Petersen 		}
38166014759cSMartin K. Petersen 		if (errsts)
38176014759cSMartin K. Petersen 			break;
381844d92694SMartin K. Petersen 		errsts = check_readiness(SCpnt, 0, devip);
381944d92694SMartin K. Petersen 		if (errsts)
382044d92694SMartin K. Petersen 			break;
382144d92694SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
382244d92694SMartin K. Petersen 		errsts = resp_write_same(SCpnt, lba, num, devip, ei_lba, unmap);
382344d92694SMartin K. Petersen 		break;
382444d92694SMartin K. Petersen 	case UNMAP:
382544d92694SMartin K. Petersen 		errsts = check_readiness(SCpnt, 0, devip);
382644d92694SMartin K. Petersen 		if (errsts)
382744d92694SMartin K. Petersen 			break;
382844d92694SMartin K. Petersen 
38295b94e232SMartin K. Petersen 		if (scsi_debug_unmap_max_desc == 0 || scsi_debug_lbpu == 0) {
383044d92694SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
383144d92694SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
383244d92694SMartin K. Petersen 			errsts = check_condition_result;
383344d92694SMartin K. Petersen 		} else
383444d92694SMartin K. Petersen 			errsts = resp_unmap(SCpnt, devip);
383544d92694SMartin K. Petersen 		break;
3836639db475SFUJITA Tomonori 	case MODE_SENSE:
3837639db475SFUJITA Tomonori 	case MODE_SENSE_10:
3838639db475SFUJITA Tomonori 		errsts = resp_mode_sense(SCpnt, target, devip);
3839639db475SFUJITA Tomonori 		break;
3840639db475SFUJITA Tomonori 	case MODE_SELECT:
3841639db475SFUJITA Tomonori 		errsts = resp_mode_select(SCpnt, 1, devip);
3842639db475SFUJITA Tomonori 		break;
3843639db475SFUJITA Tomonori 	case MODE_SELECT_10:
3844639db475SFUJITA Tomonori 		errsts = resp_mode_select(SCpnt, 0, devip);
3845639db475SFUJITA Tomonori 		break;
3846639db475SFUJITA Tomonori 	case LOG_SENSE:
3847639db475SFUJITA Tomonori 		errsts = resp_log_sense(SCpnt, devip);
3848639db475SFUJITA Tomonori 		break;
3849639db475SFUJITA Tomonori 	case SYNCHRONIZE_CACHE:
3850639db475SFUJITA Tomonori 		delay_override = 1;
3851639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3852639db475SFUJITA Tomonori 		break;
3853639db475SFUJITA Tomonori 	case WRITE_BUFFER:
3854639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3855639db475SFUJITA Tomonori 		break;
3856639db475SFUJITA Tomonori 	case XDWRITEREAD_10:
3857639db475SFUJITA Tomonori 		if (!scsi_bidi_cmnd(SCpnt)) {
3858639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3859639db475SFUJITA Tomonori 					INVALID_FIELD_IN_CDB, 0);
3860639db475SFUJITA Tomonori 			errsts = check_condition_result;
3861639db475SFUJITA Tomonori 			break;
3862639db475SFUJITA Tomonori 		}
3863639db475SFUJITA Tomonori 
3864639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3865639db475SFUJITA Tomonori 		if (errsts)
3866639db475SFUJITA Tomonori 			break;
3867639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
3868639db475SFUJITA Tomonori 			break;
3869395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3870395cef03SMartin K. Petersen 		errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
3871639db475SFUJITA Tomonori 		if (errsts)
3872639db475SFUJITA Tomonori 			break;
3873395cef03SMartin K. Petersen 		errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
3874639db475SFUJITA Tomonori 		if (errsts)
3875639db475SFUJITA Tomonori 			break;
3876639db475SFUJITA Tomonori 		errsts = resp_xdwriteread(SCpnt, lba, num, devip);
3877639db475SFUJITA Tomonori 		break;
3878395cef03SMartin K. Petersen 	case VARIABLE_LENGTH_CMD:
3879395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
3880395cef03SMartin K. Petersen 
3881395cef03SMartin K. Petersen 			if ((cmd[10] & 0xe0) == 0)
3882395cef03SMartin K. Petersen 				printk(KERN_ERR
3883395cef03SMartin K. Petersen 				       "Unprotected RD/WR to DIF device\n");
3884395cef03SMartin K. Petersen 
3885395cef03SMartin K. Petersen 			if (cmd[9] == READ_32) {
3886395cef03SMartin K. Petersen 				BUG_ON(SCpnt->cmd_len < 32);
3887395cef03SMartin K. Petersen 				goto read;
3888395cef03SMartin K. Petersen 			}
3889395cef03SMartin K. Petersen 
3890395cef03SMartin K. Petersen 			if (cmd[9] == WRITE_32) {
3891395cef03SMartin K. Petersen 				BUG_ON(SCpnt->cmd_len < 32);
3892395cef03SMartin K. Petersen 				goto write;
3893395cef03SMartin K. Petersen 			}
3894395cef03SMartin K. Petersen 		}
3895395cef03SMartin K. Petersen 
3896395cef03SMartin K. Petersen 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
3897395cef03SMartin K. Petersen 				INVALID_FIELD_IN_CDB, 0);
3898395cef03SMartin K. Petersen 		errsts = check_condition_result;
3899395cef03SMartin K. Petersen 		break;
3900395cef03SMartin K. Petersen 
3901639db475SFUJITA Tomonori 	default:
3902639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3903639db475SFUJITA Tomonori 			printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
3904639db475SFUJITA Tomonori 			       "supported\n", *cmd);
3905639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3906639db475SFUJITA Tomonori 		if (errsts)
3907639db475SFUJITA Tomonori 			break;	/* Unit attention takes precedence */
3908639db475SFUJITA Tomonori 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
3909639db475SFUJITA Tomonori 		errsts = check_condition_result;
3910639db475SFUJITA Tomonori 		break;
3911639db475SFUJITA Tomonori 	}
3912639db475SFUJITA Tomonori 	return schedule_resp(SCpnt, devip, done, errsts,
3913639db475SFUJITA Tomonori 			     (delay_override ? 0 : scsi_debug_delay));
3914639db475SFUJITA Tomonori }
3915639db475SFUJITA Tomonori 
3916f281233dSJeff Garzik static DEF_SCSI_QCMD(scsi_debug_queuecommand)
3917f281233dSJeff Garzik 
39189e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
39199e603ca0SFUJITA Tomonori 	.proc_info =		scsi_debug_proc_info,
39209e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
39219e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
39229e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
39239e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
39249e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
39259e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
39269e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
39279e603ca0SFUJITA Tomonori 	.queuecommand =		scsi_debug_queuecommand,
39289e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
39299e603ca0SFUJITA Tomonori 	.eh_bus_reset_handler = scsi_debug_bus_reset,
39309e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
39319e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
39329e603ca0SFUJITA Tomonori 	.bios_param =		scsi_debug_biosparam,
39339e603ca0SFUJITA Tomonori 	.can_queue =		SCSI_DEBUG_CANQUEUE,
39349e603ca0SFUJITA Tomonori 	.this_id =		7,
39359e603ca0SFUJITA Tomonori 	.sg_tablesize =		256,
39369e603ca0SFUJITA Tomonori 	.cmd_per_lun =		16,
39379e603ca0SFUJITA Tomonori 	.max_sectors =		0xffff,
39389e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
39399e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
39409e603ca0SFUJITA Tomonori };
39419e603ca0SFUJITA Tomonori 
39421da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev)
39431da177e4SLinus Torvalds {
39441da177e4SLinus Torvalds         int error = 0;
39451da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
39461da177e4SLinus Torvalds         struct Scsi_Host *hpnt;
3947c6a44287SMartin K. Petersen 	int host_prot;
39481da177e4SLinus Torvalds 
39491da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
39501da177e4SLinus Torvalds 
395178d4e5a0SDouglas Gilbert 	sdebug_driver_template.can_queue = scsi_debug_max_queue;
39521da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
39531da177e4SLinus Torvalds 	if (NULL == hpnt) {
3954cadbd4a5SHarvey Harrison 		printk(KERN_ERR "%s: scsi_register failed\n", __func__);
39551da177e4SLinus Torvalds 		error = -ENODEV;
39561da177e4SLinus Torvalds 		return error;
39571da177e4SLinus Torvalds 	}
39581da177e4SLinus Torvalds 
39591da177e4SLinus Torvalds         sdbg_host->shost = hpnt;
39601da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
39611da177e4SLinus Torvalds 	if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
39621da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts + 1;
39631da177e4SLinus Torvalds 	else
39641da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts;
3965c65b1445SDouglas Gilbert 	hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;	/* = scsi_debug_max_luns; */
39661da177e4SLinus Torvalds 
3967c6a44287SMartin K. Petersen 	host_prot = 0;
3968c6a44287SMartin K. Petersen 
3969c6a44287SMartin K. Petersen 	switch (scsi_debug_dif) {
3970c6a44287SMartin K. Petersen 
3971c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
3972c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE1_PROTECTION;
3973c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
3974c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE1_PROTECTION;
3975c6a44287SMartin K. Petersen 		break;
3976c6a44287SMartin K. Petersen 
3977c6a44287SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
3978c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE2_PROTECTION;
3979c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
3980c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE2_PROTECTION;
3981c6a44287SMartin K. Petersen 		break;
3982c6a44287SMartin K. Petersen 
3983c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
3984c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE3_PROTECTION;
3985c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
3986c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE3_PROTECTION;
3987c6a44287SMartin K. Petersen 		break;
3988c6a44287SMartin K. Petersen 
3989c6a44287SMartin K. Petersen 	default:
3990c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
3991c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE0_PROTECTION;
3992c6a44287SMartin K. Petersen 		break;
3993c6a44287SMartin K. Petersen 	}
3994c6a44287SMartin K. Petersen 
3995c6a44287SMartin K. Petersen 	scsi_host_set_prot(hpnt, host_prot);
3996c6a44287SMartin K. Petersen 
3997c6a44287SMartin K. Petersen 	printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
3998c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
3999c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
4000c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
4001c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
4002c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
4003c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
4004c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
4005c6a44287SMartin K. Petersen 
4006c6a44287SMartin K. Petersen 	if (scsi_debug_guard == 1)
4007c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
4008c6a44287SMartin K. Petersen 	else
4009c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
4010c6a44287SMartin K. Petersen 
40111da177e4SLinus Torvalds         error = scsi_add_host(hpnt, &sdbg_host->dev);
40121da177e4SLinus Torvalds         if (error) {
4013cadbd4a5SHarvey Harrison                 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
40141da177e4SLinus Torvalds                 error = -ENODEV;
40151da177e4SLinus Torvalds 		scsi_host_put(hpnt);
40161da177e4SLinus Torvalds         } else
40171da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
40181da177e4SLinus Torvalds 
40191da177e4SLinus Torvalds 
40201da177e4SLinus Torvalds         return error;
40211da177e4SLinus Torvalds }
40221da177e4SLinus Torvalds 
40231da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev)
40241da177e4SLinus Torvalds {
40251da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
40268b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
40271da177e4SLinus Torvalds 
40281da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
40291da177e4SLinus Torvalds 
40301da177e4SLinus Torvalds 	if (!sdbg_host) {
40311da177e4SLinus Torvalds 		printk(KERN_ERR "%s: Unable to locate host info\n",
4032cadbd4a5SHarvey Harrison 		       __func__);
40331da177e4SLinus Torvalds 		return -ENODEV;
40341da177e4SLinus Torvalds 	}
40351da177e4SLinus Torvalds 
40361da177e4SLinus Torvalds         scsi_remove_host(sdbg_host->shost);
40371da177e4SLinus Torvalds 
40388b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
40398b40228fSFUJITA Tomonori 				 dev_list) {
40401da177e4SLinus Torvalds                 list_del(&sdbg_devinfo->dev_list);
40411da177e4SLinus Torvalds                 kfree(sdbg_devinfo);
40421da177e4SLinus Torvalds         }
40431da177e4SLinus Torvalds 
40441da177e4SLinus Torvalds         scsi_host_put(sdbg_host->shost);
40451da177e4SLinus Torvalds         return 0;
40461da177e4SLinus Torvalds }
40471da177e4SLinus Torvalds 
40488dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
40498dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
40501da177e4SLinus Torvalds {
40518dea0d02SFUJITA Tomonori 	return 1;
40528dea0d02SFUJITA Tomonori }
40531da177e4SLinus Torvalds 
40548dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
40558dea0d02SFUJITA Tomonori 	.name = "pseudo",
40568dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
40578dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
40588dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
40598dea0d02SFUJITA Tomonori };
4060