xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision a87e3a67)
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  */
921da177e4SLinus Torvalds #define DEF_DELAY   1
931da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
941da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
951da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
961da177e4SLinus Torvalds #define DEF_OPTS   0
971da177e4SLinus Torvalds #define DEF_SCSI_LEVEL   5    /* INQUIRY, byte2 [5->SPC-3] */
981da177e4SLinus Torvalds #define DEF_PTYPE   0
991da177e4SLinus Torvalds #define DEF_D_SENSE   0
100c65b1445SDouglas Gilbert #define DEF_NO_LUN_0   0
101c65b1445SDouglas Gilbert #define DEF_VIRTUAL_GB   0
10223183910SDouglas Gilbert #define DEF_FAKE_RW	0
10323183910SDouglas Gilbert #define DEF_VPD_USE_HOSTNO 1
104597136abSMartin K. Petersen #define DEF_SECTOR_SIZE 512
105c6a44287SMartin K. Petersen #define DEF_DIX 0
106c6a44287SMartin K. Petersen #define DEF_DIF 0
107c6a44287SMartin K. Petersen #define DEF_GUARD 0
108c6a44287SMartin K. Petersen #define DEF_ATO 1
109ea61fca5SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
110ea61fca5SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
111e308b3d1SMartin K. Petersen #define DEF_OPT_BLKS 64
1126014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1136014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1146014759cSMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
11544d92694SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1166014759cSMartin K. Petersen #define DEF_TPWS 0
1176014759cSMartin K. Petersen #define DEF_TPU 0
1181da177e4SLinus Torvalds 
1191da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */
1201da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE   1
1211da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR   2
1221da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT   4
1231da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR   8
1246f3cbf55SDouglas Gilbert #define SCSI_DEBUG_OPT_TRANSPORT_ERR   16
125c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIF_ERR   32
126c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIX_ERR   64
1271da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
1281da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1291da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1301da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1316f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1326f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1331da177e4SLinus Torvalds  *
1341da177e4SLinus Torvalds  * When "every_nth" < 0 then after "- every_nth" commands:
1351da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1361da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1371da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1386f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1396f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1401da177e4SLinus Torvalds  * This will continue until some other action occurs (e.g. the user
1411da177e4SLinus Torvalds  * writing a new value (other than -1 or 1) to every_nth via sysfs).
1421da177e4SLinus Torvalds  */
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
1451da177e4SLinus Torvalds  * sector on read commands: */
1461da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
1491da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
1501da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
151c65b1445SDouglas Gilbert #define SAM2_WLUN_REPORT_LUNS 0xc101
1521da177e4SLinus Torvalds 
15378d4e5a0SDouglas Gilbert /* Can queue up to this number of commands. Typically commands that
15478d4e5a0SDouglas Gilbert  * that have a non-zero delay are queued. */
15578d4e5a0SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE  255
15678d4e5a0SDouglas Gilbert 
1571da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST;
1581da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY;
1591da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
1601da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH;
1611da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS;
16278d4e5a0SDouglas Gilbert static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE;
1631da177e4SLinus Torvalds static int scsi_debug_num_parts = DEF_NUM_PARTS;
16478d4e5a0SDouglas Gilbert static int scsi_debug_no_uld = 0;
1651da177e4SLinus Torvalds static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
1661da177e4SLinus Torvalds static int scsi_debug_opts = DEF_OPTS;
1671da177e4SLinus Torvalds static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
1681da177e4SLinus Torvalds static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
1691da177e4SLinus Torvalds static int scsi_debug_dsense = DEF_D_SENSE;
170c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
171c65b1445SDouglas Gilbert static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
17223183910SDouglas Gilbert static int scsi_debug_fake_rw = DEF_FAKE_RW;
17323183910SDouglas Gilbert static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
174597136abSMartin K. Petersen static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
175c6a44287SMartin K. Petersen static int scsi_debug_dix = DEF_DIX;
176c6a44287SMartin K. Petersen static int scsi_debug_dif = DEF_DIF;
177c6a44287SMartin K. Petersen static int scsi_debug_guard = DEF_GUARD;
178c6a44287SMartin K. Petersen static int scsi_debug_ato = DEF_ATO;
179ea61fca5SMartin K. Petersen static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
180ea61fca5SMartin K. Petersen static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
181e308b3d1SMartin K. Petersen static int scsi_debug_opt_blks = DEF_OPT_BLKS;
1826014759cSMartin K. Petersen static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
1836014759cSMartin K. Petersen static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
1846014759cSMartin K. Petersen static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
1856014759cSMartin K. Petersen static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
1866014759cSMartin K. Petersen static unsigned int scsi_debug_tpws = DEF_TPWS;
1876014759cSMartin K. Petersen static unsigned int scsi_debug_tpu = DEF_TPU;
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds static int scsi_debug_cmnd_count = 0;
1901da177e4SLinus Torvalds 
1911da177e4SLinus Torvalds #define DEV_READONLY(TGT)      (0)
1921da177e4SLinus Torvalds #define DEV_REMOVEABLE(TGT)    (0)
1931da177e4SLinus Torvalds 
194c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
1951da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
1961da177e4SLinus Torvalds 
1971da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
1981da177e4SLinus Torvalds    may still need them */
1991da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
2001da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
2011da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4
2041da177e4SLinus Torvalds 
2051da177e4SLinus Torvalds #define SDEBUG_SENSE_LEN 32
2061da177e4SLinus Torvalds 
207395cef03SMartin K. Petersen #define SCSI_DEBUG_MAX_CMD_LEN 32
2089e603ca0SFUJITA Tomonori 
2091da177e4SLinus Torvalds struct sdebug_dev_info {
2101da177e4SLinus Torvalds 	struct list_head dev_list;
2111da177e4SLinus Torvalds 	unsigned char sense_buff[SDEBUG_SENSE_LEN];	/* weak nexus */
2121da177e4SLinus Torvalds 	unsigned int channel;
2131da177e4SLinus Torvalds 	unsigned int target;
2141da177e4SLinus Torvalds 	unsigned int lun;
2151da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
216c65b1445SDouglas Gilbert 	unsigned int wlun;
2171da177e4SLinus Torvalds 	char reset;
218c65b1445SDouglas Gilbert 	char stopped;
2191da177e4SLinus Torvalds 	char used;
2201da177e4SLinus Torvalds };
2211da177e4SLinus Torvalds 
2221da177e4SLinus Torvalds struct sdebug_host_info {
2231da177e4SLinus Torvalds 	struct list_head host_list;
2241da177e4SLinus Torvalds 	struct Scsi_Host *shost;
2251da177e4SLinus Torvalds 	struct device dev;
2261da177e4SLinus Torvalds 	struct list_head dev_info_list;
2271da177e4SLinus Torvalds };
2281da177e4SLinus Torvalds 
2291da177e4SLinus Torvalds #define to_sdebug_host(d)	\
2301da177e4SLinus Torvalds 	container_of(d, struct sdebug_host_info, dev)
2311da177e4SLinus Torvalds 
2321da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
2331da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
2341da177e4SLinus Torvalds 
2351da177e4SLinus Torvalds typedef void (* done_funct_t) (struct scsi_cmnd *);
2361da177e4SLinus Torvalds 
2371da177e4SLinus Torvalds struct sdebug_queued_cmd {
2381da177e4SLinus Torvalds 	int in_use;
2391da177e4SLinus Torvalds 	struct timer_list cmnd_timer;
2401da177e4SLinus Torvalds 	done_funct_t done_funct;
2411da177e4SLinus Torvalds 	struct scsi_cmnd * a_cmnd;
2421da177e4SLinus Torvalds 	int scsi_result;
2431da177e4SLinus Torvalds };
2441da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds static unsigned char * fake_storep;	/* ramdisk storage */
247c6a44287SMartin K. Petersen static unsigned char *dif_storep;	/* protection info */
24844d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
2491da177e4SLinus Torvalds 
25044d92694SMartin K. Petersen static unsigned long map_size;
2511da177e4SLinus Torvalds static int num_aborts = 0;
2521da177e4SLinus Torvalds static int num_dev_resets = 0;
2531da177e4SLinus Torvalds static int num_bus_resets = 0;
2541da177e4SLinus Torvalds static int num_host_resets = 0;
255c6a44287SMartin K. Petersen static int dix_writes;
256c6a44287SMartin K. Petersen static int dix_reads;
257c6a44287SMartin K. Petersen static int dif_errors;
2581da177e4SLinus Torvalds 
2591da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock);
2601da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds static char sdebug_proc_name[] = "scsi_debug";
2631da177e4SLinus Torvalds 
2641da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
2651da177e4SLinus Torvalds 
266c6a44287SMartin K. Petersen static inline sector_t dif_offset(sector_t sector)
267c6a44287SMartin K. Petersen {
268c6a44287SMartin K. Petersen 	return sector << 3;
269c6a44287SMartin K. Petersen }
270c6a44287SMartin K. Petersen 
2711da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
2721da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
2731da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
2741da177e4SLinus Torvalds };
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds static const int check_condition_result =
2771da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
2781da177e4SLinus Torvalds 
279c6a44287SMartin K. Petersen static const int illegal_condition_result =
280c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
281c6a44287SMartin K. Petersen 
282c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
283c65b1445SDouglas Gilbert 				    0, 0, 0x2, 0x4b};
284c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
285c65b1445SDouglas Gilbert 			           0, 0, 0x0, 0x0};
286c65b1445SDouglas Gilbert 
2871da177e4SLinus Torvalds static int sdebug_add_adapter(void);
2881da177e4SLinus Torvalds static void sdebug_remove_adapter(void);
2891da177e4SLinus Torvalds 
2908dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
2918dea0d02SFUJITA Tomonori {
2928dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
2938dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
2948dea0d02SFUJITA Tomonori 
2958dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
2968dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2978dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
2988dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
2998dea0d02SFUJITA Tomonori 		    (scsi_debug_num_tgts > hpnt->this_id))
3008dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts + 1;
3018dea0d02SFUJITA Tomonori 		else
3028dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts;
3038dea0d02SFUJITA Tomonori 		/* scsi_debug_max_luns; */
3048dea0d02SFUJITA Tomonori 		hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
3058dea0d02SFUJITA Tomonori 	}
3068dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
3078dea0d02SFUJITA Tomonori }
3088dea0d02SFUJITA Tomonori 
3098dea0d02SFUJITA Tomonori static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
3108dea0d02SFUJITA Tomonori 			    int asc, int asq)
3118dea0d02SFUJITA Tomonori {
3128dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
3138dea0d02SFUJITA Tomonori 
3148dea0d02SFUJITA Tomonori 	sbuff = devip->sense_buff;
3158dea0d02SFUJITA Tomonori 	memset(sbuff, 0, SDEBUG_SENSE_LEN);
3168dea0d02SFUJITA Tomonori 
3178dea0d02SFUJITA Tomonori 	scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
3188dea0d02SFUJITA Tomonori 
3198dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3208dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug:    [sense_key,asc,ascq]: "
3218dea0d02SFUJITA Tomonori 		      "[0x%x,0x%x,0x%x]\n", key, asc, asq);
3228dea0d02SFUJITA Tomonori }
3231da177e4SLinus Torvalds 
3243de9f944SFUJITA Tomonori static void get_data_transfer_info(unsigned char *cmd,
325395cef03SMartin K. Petersen 				   unsigned long long *lba, unsigned int *num,
326395cef03SMartin K. Petersen 				   u32 *ei_lba)
3273de9f944SFUJITA Tomonori {
328395cef03SMartin K. Petersen 	*ei_lba = 0;
329395cef03SMartin K. Petersen 
3303de9f944SFUJITA Tomonori 	switch (*cmd) {
331395cef03SMartin K. Petersen 	case VARIABLE_LENGTH_CMD:
332395cef03SMartin K. Petersen 		*lba = (u64)cmd[19] | (u64)cmd[18] << 8 |
333395cef03SMartin K. Petersen 			(u64)cmd[17] << 16 | (u64)cmd[16] << 24 |
334395cef03SMartin K. Petersen 			(u64)cmd[15] << 32 | (u64)cmd[14] << 40 |
335395cef03SMartin K. Petersen 			(u64)cmd[13] << 48 | (u64)cmd[12] << 56;
336395cef03SMartin K. Petersen 
337395cef03SMartin K. Petersen 		*ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 |
338395cef03SMartin K. Petersen 			(u32)cmd[21] << 16 | (u32)cmd[20] << 24;
339395cef03SMartin K. Petersen 
340395cef03SMartin K. Petersen 		*num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 |
341395cef03SMartin K. Petersen 			(u32)cmd[28] << 24;
342395cef03SMartin K. Petersen 		break;
343395cef03SMartin K. Petersen 
34444d92694SMartin K. Petersen 	case WRITE_SAME_16:
3453de9f944SFUJITA Tomonori 	case WRITE_16:
3463de9f944SFUJITA Tomonori 	case READ_16:
347d5cdc989SFUJITA Tomonori 		*lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
348d5cdc989SFUJITA Tomonori 			(u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
349d5cdc989SFUJITA Tomonori 			(u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
350d5cdc989SFUJITA Tomonori 			(u64)cmd[3] << 48 | (u64)cmd[2] << 56;
351d5cdc989SFUJITA Tomonori 
352d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
353d5cdc989SFUJITA Tomonori 			(u32)cmd[10] << 24;
3543de9f944SFUJITA Tomonori 		break;
3553de9f944SFUJITA Tomonori 	case WRITE_12:
3563de9f944SFUJITA Tomonori 	case READ_12:
357d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
358d5cdc989SFUJITA Tomonori 			(u32)cmd[2] << 24;
359d5cdc989SFUJITA Tomonori 
360d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
361d5cdc989SFUJITA Tomonori 			(u32)cmd[6] << 24;
3623de9f944SFUJITA Tomonori 		break;
36344d92694SMartin K. Petersen 	case WRITE_SAME:
3643de9f944SFUJITA Tomonori 	case WRITE_10:
3653de9f944SFUJITA Tomonori 	case READ_10:
366c639d14eSFUJITA Tomonori 	case XDWRITEREAD_10:
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[8] | (u32)cmd[7] << 8;
3713de9f944SFUJITA Tomonori 		break;
3723de9f944SFUJITA Tomonori 	case WRITE_6:
3733de9f944SFUJITA Tomonori 	case READ_6:
374d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
375d5cdc989SFUJITA Tomonori 			(u32)(cmd[1] & 0x1f) << 16;
3763de9f944SFUJITA Tomonori 		*num = (0 == cmd[4]) ? 256 : cmd[4];
3773de9f944SFUJITA Tomonori 		break;
3783de9f944SFUJITA Tomonori 	default:
3793de9f944SFUJITA Tomonori 		break;
3803de9f944SFUJITA Tomonori 	}
3813de9f944SFUJITA Tomonori }
3821da177e4SLinus Torvalds 
3831da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
3841da177e4SLinus Torvalds {
3851da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
3861da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
3871da177e4SLinus Torvalds 	}
3881da177e4SLinus Torvalds 	return -EINVAL;
3891da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
3901da177e4SLinus Torvalds }
3911da177e4SLinus Torvalds 
392c65b1445SDouglas Gilbert static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
393c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
3941da177e4SLinus Torvalds {
3951da177e4SLinus Torvalds 	if (devip->reset) {
3961da177e4SLinus Torvalds 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3971da177e4SLinus Torvalds 			printk(KERN_INFO "scsi_debug: Reporting Unit "
3981da177e4SLinus Torvalds 			       "attention: power on reset\n");
3991da177e4SLinus Torvalds 		devip->reset = 0;
4001da177e4SLinus Torvalds 		mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
4011da177e4SLinus Torvalds 		return check_condition_result;
4021da177e4SLinus Torvalds 	}
403c65b1445SDouglas Gilbert 	if ((0 == reset_only) && devip->stopped) {
404c65b1445SDouglas Gilbert 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
405c65b1445SDouglas Gilbert 			printk(KERN_INFO "scsi_debug: Reporting Not "
406c65b1445SDouglas Gilbert 			       "ready: initializing command required\n");
407c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
408c65b1445SDouglas Gilbert 				0x2);
409c65b1445SDouglas Gilbert 		return check_condition_result;
410c65b1445SDouglas Gilbert 	}
4111da177e4SLinus Torvalds 	return 0;
4121da177e4SLinus Torvalds }
4131da177e4SLinus Torvalds 
4141da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
4151da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
4161da177e4SLinus Torvalds 				int arr_len)
4171da177e4SLinus Torvalds {
41821a61829SFUJITA Tomonori 	int act_len;
419072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
4201da177e4SLinus Torvalds 
421072d0bb3SFUJITA Tomonori 	if (!sdb->length)
4221da177e4SLinus Torvalds 		return 0;
423072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
4241da177e4SLinus Torvalds 		return (DID_ERROR << 16);
42521a61829SFUJITA Tomonori 
42621a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
42721a61829SFUJITA Tomonori 				      arr, arr_len);
428072d0bb3SFUJITA Tomonori 	if (sdb->resid)
429072d0bb3SFUJITA Tomonori 		sdb->resid -= act_len;
430c65b1445SDouglas Gilbert 	else
43121a61829SFUJITA Tomonori 		sdb->resid = scsi_bufflen(scp) - act_len;
43221a61829SFUJITA Tomonori 
4331da177e4SLinus Torvalds 	return 0;
4341da177e4SLinus Torvalds }
4351da177e4SLinus Torvalds 
4361da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */
4371da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
43821a61829SFUJITA Tomonori 			       int arr_len)
4391da177e4SLinus Torvalds {
44021a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
4411da177e4SLinus Torvalds 		return 0;
442072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
4431da177e4SLinus Torvalds 		return -1;
44421a61829SFUJITA Tomonori 
44521a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
4461da177e4SLinus Torvalds }
4471da177e4SLinus Torvalds 
4481da177e4SLinus Torvalds 
4491da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux   ";
4501da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug      ";
4511da177e4SLinus Torvalds static const char * inq_product_rev = "0004";
4521da177e4SLinus Torvalds 
4535a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
4545a09e398SHannes Reinecke 			   int target_dev_id, int dev_id_num,
4555a09e398SHannes Reinecke 			   const char * dev_id_str,
456c65b1445SDouglas Gilbert 			   int dev_id_str_len)
4571da177e4SLinus Torvalds {
458c65b1445SDouglas Gilbert 	int num, port_a;
459c65b1445SDouglas Gilbert 	char b[32];
4601da177e4SLinus Torvalds 
461c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
4621da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
4631da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
4641da177e4SLinus Torvalds 	arr[1] = 0x1;
4651da177e4SLinus Torvalds 	arr[2] = 0x0;
4661da177e4SLinus Torvalds 	memcpy(&arr[4], inq_vendor_id, 8);
4671da177e4SLinus Torvalds 	memcpy(&arr[12], inq_product_id, 16);
4681da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
4691da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
4701da177e4SLinus Torvalds 	arr[3] = num;
4711da177e4SLinus Torvalds 	num += 4;
472c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
473c65b1445SDouglas Gilbert 		/* NAA-5, Logical unit identifier (binary) */
474c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* binary (not necessarily sas) */
475c65b1445SDouglas Gilbert 		arr[num++] = 0x3;	/* PIV=0, lu, naa */
476c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
477c65b1445SDouglas Gilbert 		arr[num++] = 0x8;
478c65b1445SDouglas Gilbert 		arr[num++] = 0x53;  /* naa-5 ieee company id=0x333333 (fake) */
479c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
480c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
481c65b1445SDouglas Gilbert 		arr[num++] = 0x30;
482c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 24);
483c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 16) & 0xff;
484c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 8) & 0xff;
485c65b1445SDouglas Gilbert 		arr[num++] = dev_id_num & 0xff;
486c65b1445SDouglas Gilbert 		/* Target relative port number */
487c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
488c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
489c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
490c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
491c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
492c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
493c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
494c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
495c65b1445SDouglas Gilbert 	}
496c65b1445SDouglas Gilbert 	/* NAA-5, Target port identifier */
497c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
498c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
499c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
500c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
501c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
502c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
503c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
504c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
505c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
506c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
507c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
508c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
5095a09e398SHannes Reinecke 	/* NAA-5, Target port group identifier */
5105a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
5115a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
5125a09e398SHannes Reinecke 	arr[num++] = 0x0;
5135a09e398SHannes Reinecke 	arr[num++] = 0x4;
5145a09e398SHannes Reinecke 	arr[num++] = 0;
5155a09e398SHannes Reinecke 	arr[num++] = 0;
5165a09e398SHannes Reinecke 	arr[num++] = (port_group_id >> 8) & 0xff;
5175a09e398SHannes Reinecke 	arr[num++] = port_group_id & 0xff;
518c65b1445SDouglas Gilbert 	/* NAA-5, Target device identifier */
519c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
520c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
521c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
522c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
523c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
524c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
525c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
526c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
527c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 24);
528c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 16) & 0xff;
529c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 8) & 0xff;
530c65b1445SDouglas Gilbert 	arr[num++] = target_dev_id & 0xff;
531c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
532c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
533c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
534c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
535c65b1445SDouglas Gilbert 	arr[num++] = 24;
536c65b1445SDouglas Gilbert 	memcpy(arr + num, "naa.52222220", 12);
537c65b1445SDouglas Gilbert 	num += 12;
538c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
539c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
540c65b1445SDouglas Gilbert 	num += 8;
541c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
542c65b1445SDouglas Gilbert 	num += 4;
543c65b1445SDouglas Gilbert 	return num;
544c65b1445SDouglas Gilbert }
545c65b1445SDouglas Gilbert 
546c65b1445SDouglas Gilbert 
547c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
548c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
549c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
550c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
551c65b1445SDouglas Gilbert };
552c65b1445SDouglas Gilbert 
553c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr)
554c65b1445SDouglas Gilbert {
555c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
556c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
557c65b1445SDouglas Gilbert }
558c65b1445SDouglas Gilbert 
559c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr)
560c65b1445SDouglas Gilbert {
561c65b1445SDouglas Gilbert 	int num = 0;
562c65b1445SDouglas Gilbert 	const char * na1 = "https://www.kernel.org/config";
563c65b1445SDouglas Gilbert 	const char * na2 = "http://www.kernel.org/log";
564c65b1445SDouglas Gilbert 	int plen, olen;
565c65b1445SDouglas Gilbert 
566c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
567c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
568c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
569c65b1445SDouglas Gilbert 	olen = strlen(na1);
570c65b1445SDouglas Gilbert 	plen = olen + 1;
571c65b1445SDouglas Gilbert 	if (plen % 4)
572c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
573c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
574c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
575c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
576c65b1445SDouglas Gilbert 	num += plen;
577c65b1445SDouglas Gilbert 
578c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
579c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
580c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
581c65b1445SDouglas Gilbert 	olen = strlen(na2);
582c65b1445SDouglas Gilbert 	plen = olen + 1;
583c65b1445SDouglas Gilbert 	if (plen % 4)
584c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
585c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
586c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
587c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
588c65b1445SDouglas Gilbert 	num += plen;
589c65b1445SDouglas Gilbert 
590c65b1445SDouglas Gilbert 	return num;
591c65b1445SDouglas Gilbert }
592c65b1445SDouglas Gilbert 
593c65b1445SDouglas Gilbert /* SCSI ports VPD page */
594c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
595c65b1445SDouglas Gilbert {
596c65b1445SDouglas Gilbert 	int num = 0;
597c65b1445SDouglas Gilbert 	int port_a, port_b;
598c65b1445SDouglas Gilbert 
599c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
600c65b1445SDouglas Gilbert 	port_b = port_a + 1;
601c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
602c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
603c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
604c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
605c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
606c65b1445SDouglas Gilbert 	num += 6;
607c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
608c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
609c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
610c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
611c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
612c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
613c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
614c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
615c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
616c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
617c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
618c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
619c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
620c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
621c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
622c65b1445SDouglas Gilbert 
623c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
624c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
625c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
626c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
627c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
628c65b1445SDouglas Gilbert 	num += 6;
629c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
630c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
631c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
632c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
633c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
634c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
635c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
636c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
637c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
638c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
639c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
640c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 24);
641c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 16) & 0xff;
642c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 8) & 0xff;
643c65b1445SDouglas Gilbert 	arr[num++] = port_b & 0xff;
644c65b1445SDouglas Gilbert 
645c65b1445SDouglas Gilbert 	return num;
646c65b1445SDouglas Gilbert }
647c65b1445SDouglas Gilbert 
648c65b1445SDouglas Gilbert 
649c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
650c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
651c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
652c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
653c65b1445SDouglas Gilbert '1','2','3','4',
654c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
655c65b1445SDouglas Gilbert 0xec,0,0,0,
656c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
657c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
658c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
659c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
660c65b1445SDouglas Gilbert 0x53,0x41,
661c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
662c65b1445SDouglas Gilbert 0x20,0x20,
663c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
664c65b1445SDouglas Gilbert 0x10,0x80,
665c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
666c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
667c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
668c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
669c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
670c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
671c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
672c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
673c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
674c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
675c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
676c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
677c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
678c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
679c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
680c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
681c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,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 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
686c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
687c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
688c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
689c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
690c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
691c65b1445SDouglas Gilbert };
692c65b1445SDouglas Gilbert 
693c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr)
694c65b1445SDouglas Gilbert {
695c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
696c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
697c65b1445SDouglas Gilbert }
698c65b1445SDouglas Gilbert 
699c65b1445SDouglas Gilbert 
7001e49f785SDouglas Gilbert /* Block limits VPD page (SBC-3) */
701c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
7021e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
7031e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7041e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7051e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
706c65b1445SDouglas Gilbert };
707c65b1445SDouglas Gilbert 
708c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr)
709c65b1445SDouglas Gilbert {
710ea61fca5SMartin K. Petersen 	unsigned int gran;
711ea61fca5SMartin K. Petersen 
712c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
713e308b3d1SMartin K. Petersen 
714e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
715ea61fca5SMartin K. Petersen 	gran = 1 << scsi_debug_physblk_exp;
716ea61fca5SMartin K. Petersen 	arr[2] = (gran >> 8) & 0xff;
717ea61fca5SMartin K. Petersen 	arr[3] = gran & 0xff;
718e308b3d1SMartin K. Petersen 
719e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
720c65b1445SDouglas Gilbert 	if (sdebug_store_sectors > 0x400) {
721c65b1445SDouglas Gilbert 		arr[4] = (sdebug_store_sectors >> 24) & 0xff;
722c65b1445SDouglas Gilbert 		arr[5] = (sdebug_store_sectors >> 16) & 0xff;
723c65b1445SDouglas Gilbert 		arr[6] = (sdebug_store_sectors >> 8) & 0xff;
724c65b1445SDouglas Gilbert 		arr[7] = sdebug_store_sectors & 0xff;
725c65b1445SDouglas Gilbert 	}
72644d92694SMartin K. Petersen 
727e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
728e308b3d1SMartin K. Petersen 	put_unaligned_be32(scsi_debug_opt_blks, &arr[8]);
729e308b3d1SMartin K. Petersen 
7306014759cSMartin K. Petersen 	if (scsi_debug_tpu) {
731e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
7326014759cSMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]);
733e308b3d1SMartin K. Petersen 
734e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
73544d92694SMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
73644d92694SMartin K. Petersen 	}
73744d92694SMartin K. Petersen 
738e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
73944d92694SMartin K. Petersen 	if (scsi_debug_unmap_alignment) {
74044d92694SMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
74144d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
74244d92694SMartin K. Petersen 	}
74344d92694SMartin K. Petersen 
744e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
74544d92694SMartin K. Petersen 	put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
7466014759cSMartin K. Petersen 
74744d92694SMartin K. Petersen 	return 0x3c; /* Mandatory page length for thin provisioning */
74844d92694SMartin K. Petersen 
749c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
7501da177e4SLinus Torvalds }
7511da177e4SLinus Torvalds 
7521e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
753eac6e8e4SMatthew Wilcox static int inquiry_evpd_b1(unsigned char *arr)
754eac6e8e4SMatthew Wilcox {
755eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
756eac6e8e4SMatthew Wilcox 	arr[0] = 0;
7571e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
7581e49f785SDouglas Gilbert 	arr[2] = 0;
7591e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
760eac6e8e4SMatthew Wilcox 
761eac6e8e4SMatthew Wilcox 	return 0x3c;
762eac6e8e4SMatthew Wilcox }
7631da177e4SLinus Torvalds 
7646014759cSMartin K. Petersen /* Thin provisioning VPD page (SBC-3) */
7656014759cSMartin K. Petersen static int inquiry_evpd_b2(unsigned char *arr)
7666014759cSMartin K. Petersen {
7676014759cSMartin K. Petersen 	memset(arr, 0, 0x8);
7686014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
7696014759cSMartin K. Petersen 
7706014759cSMartin K. Petersen 	if (scsi_debug_tpu)
7716014759cSMartin K. Petersen 		arr[1] = 1 << 7;
7726014759cSMartin K. Petersen 
7736014759cSMartin K. Petersen 	if (scsi_debug_tpws)
7746014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
7756014759cSMartin K. Petersen 
7766014759cSMartin K. Petersen 	return 0x8;
7776014759cSMartin K. Petersen }
7786014759cSMartin K. Petersen 
7791da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
780c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
7811da177e4SLinus Torvalds 
7821da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd * scp, int target,
7831da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
7841da177e4SLinus Torvalds {
7851da177e4SLinus Torvalds 	unsigned char pq_pdt;
7865a09e398SHannes Reinecke 	unsigned char * arr;
7871da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
7885a09e398SHannes Reinecke 	int alloc_len, n, ret;
7891da177e4SLinus Torvalds 
7901da177e4SLinus Torvalds 	alloc_len = (cmd[3] << 8) + cmd[4];
7916f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
7926f3cbf55SDouglas Gilbert 	if (! arr)
7936f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
794c65b1445SDouglas Gilbert 	if (devip->wlun)
795c65b1445SDouglas Gilbert 		pq_pdt = 0x1e;	/* present, wlun */
796c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (0 == devip->lun))
797c65b1445SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, no device type */
798c65b1445SDouglas Gilbert 	else
7991da177e4SLinus Torvalds 		pq_pdt = (scsi_debug_ptype & 0x1f);
8001da177e4SLinus Torvalds 	arr[0] = pq_pdt;
8011da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
8021da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
8031da177e4SLinus Torvalds 			       	0);
8045a09e398SHannes Reinecke 		kfree(arr);
8051da177e4SLinus Torvalds 		return check_condition_result;
8061da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
8075a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
808c65b1445SDouglas Gilbert 		char lu_id_str[6];
809c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
8101da177e4SLinus Torvalds 
8115a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
8125a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
81323183910SDouglas Gilbert 		if (0 == scsi_debug_vpd_use_hostno)
81423183910SDouglas Gilbert 			host_no = 0;
815c65b1445SDouglas Gilbert 		lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
816c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
817c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
818c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
819c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
8201da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
821c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
822c65b1445SDouglas Gilbert 			n = 4;
823c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
824c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
825c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
826c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
827c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
828c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
829c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
830c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
831c65b1445SDouglas Gilbert 			arr[n++] = 0x89;  /* ATA information */
832c65b1445SDouglas Gilbert 			arr[n++] = 0xb0;  /* Block limits (SBC) */
833eac6e8e4SMatthew Wilcox 			arr[n++] = 0xb1;  /* Block characteristics (SBC) */
8346014759cSMartin K. Petersen 			arr[n++] = 0xb2;  /* Thin provisioning (SBC) */
835c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
8361da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
837c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
8381da177e4SLinus Torvalds 			arr[3] = len;
839c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
8401da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
841c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
8425a09e398SHannes Reinecke 			arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
8435a09e398SHannes Reinecke 						 target_dev_id, lu_id_num,
8445a09e398SHannes Reinecke 						 lu_id_str, len);
845c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
846c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
847c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_84(&arr[4]);
848c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
849c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
850c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_85(&arr[4]);
851c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
852c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
853c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
854c6a44287SMartin K. Petersen 			if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
855c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
856c6a44287SMartin K. Petersen 			else if (scsi_debug_dif)
857c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
858c6a44287SMartin K. Petersen 			else
859c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
860c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
861c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
862c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
863c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
864c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
865c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
866c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
867c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
868c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
869c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
870c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
871c65b1445SDouglas Gilbert 		} else if (0x89 == cmd[2]) { /* ATA information */
872c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
873c65b1445SDouglas Gilbert 			n = inquiry_evpd_89(&arr[4]);
874c65b1445SDouglas Gilbert 			arr[2] = (n >> 8);
875c65b1445SDouglas Gilbert 			arr[3] = (n & 0xff);
876c65b1445SDouglas Gilbert 		} else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
877c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
878c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_b0(&arr[4]);
879eac6e8e4SMatthew Wilcox 		} else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
880eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
881eac6e8e4SMatthew Wilcox 			arr[3] = inquiry_evpd_b1(&arr[4]);
8826014759cSMartin K. Petersen 		} else if (0xb2 == cmd[2]) { /* Thin provisioning (SBC) */
8836014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
8846014759cSMartin K. Petersen 			arr[3] = inquiry_evpd_b2(&arr[4]);
8851da177e4SLinus Torvalds 		} else {
8861da177e4SLinus Torvalds 			/* Illegal request, invalid field in cdb */
8871da177e4SLinus Torvalds 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
8881da177e4SLinus Torvalds 					INVALID_FIELD_IN_CDB, 0);
8895a09e398SHannes Reinecke 			kfree(arr);
8901da177e4SLinus Torvalds 			return check_condition_result;
8911da177e4SLinus Torvalds 		}
892c65b1445SDouglas Gilbert 		len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
8935a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
894c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
8955a09e398SHannes Reinecke 		kfree(arr);
8965a09e398SHannes Reinecke 		return ret;
8971da177e4SLinus Torvalds 	}
8981da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
8991da177e4SLinus Torvalds 	arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0;	/* Removable disk */
9001da177e4SLinus Torvalds 	arr[2] = scsi_debug_scsi_level;
9011da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
9021da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
903c6a44287SMartin K. Petersen 	arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
9045a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno)
9055a09e398SHannes Reinecke 		arr[5] = 0x10; /* claim: implicit TGPS */
906c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
9071da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
908c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
9091da177e4SLinus Torvalds 	memcpy(&arr[8], inq_vendor_id, 8);
9101da177e4SLinus Torvalds 	memcpy(&arr[16], inq_product_id, 16);
9111da177e4SLinus Torvalds 	memcpy(&arr[32], inq_product_rev, 4);
9121da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
913c65b1445SDouglas Gilbert 	arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
914c65b1445SDouglas Gilbert 	arr[60] = 0x3; arr[61] = 0x14;  /* SPC-3 ANSI */
915c65b1445SDouglas Gilbert 	n = 62;
9161da177e4SLinus Torvalds 	if (scsi_debug_ptype == 0) {
917c65b1445SDouglas Gilbert 		arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
9181da177e4SLinus Torvalds 	} else if (scsi_debug_ptype == 1) {
919c65b1445SDouglas Gilbert 		arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
9201da177e4SLinus Torvalds 	}
921c65b1445SDouglas Gilbert 	arr[n++] = 0xc; arr[n++] = 0xf;  /* SAS-1.1 rev 10 */
9225a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
9231da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
9245a09e398SHannes Reinecke 	kfree(arr);
9255a09e398SHannes Reinecke 	return ret;
9261da177e4SLinus Torvalds }
9271da177e4SLinus Torvalds 
9281da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp,
9291da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip)
9301da177e4SLinus Torvalds {
9311da177e4SLinus Torvalds 	unsigned char * sbuff;
9321da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
9331da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_SENSE_LEN];
934c65b1445SDouglas Gilbert 	int want_dsense;
9351da177e4SLinus Torvalds 	int len = 18;
9361da177e4SLinus Torvalds 
937c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
9381da177e4SLinus Torvalds 	if (devip->reset == 1)
939c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
940c65b1445SDouglas Gilbert 	want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
9411da177e4SLinus Torvalds 	sbuff = devip->sense_buff;
942c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
943c65b1445SDouglas Gilbert 		if (want_dsense) {
944c65b1445SDouglas Gilbert 			arr[0] = 0x72;
945c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
946c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
947c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
948c65b1445SDouglas Gilbert 		} else {
949c65b1445SDouglas Gilbert 			arr[0] = 0x70;
950c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
951c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
952c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
953c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
954c65b1445SDouglas Gilbert 		}
955c65b1445SDouglas Gilbert 	} else {
956c65b1445SDouglas Gilbert 		memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
9571da177e4SLinus Torvalds 		if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
9581da177e4SLinus Torvalds 			/* DESC bit set and sense_buff in fixed format */
959c65b1445SDouglas Gilbert 			memset(arr, 0, sizeof(arr));
9601da177e4SLinus Torvalds 			arr[0] = 0x72;
9611da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
9621da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
9631da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
9641da177e4SLinus Torvalds 			len = 8;
965c65b1445SDouglas Gilbert 		}
966c65b1445SDouglas Gilbert 	}
967c65b1445SDouglas Gilbert 	mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
9681da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
9691da177e4SLinus Torvalds }
9701da177e4SLinus Torvalds 
971c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp,
972c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
973c65b1445SDouglas Gilbert {
974c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
975c65b1445SDouglas Gilbert 	int power_cond, errsts, start;
976c65b1445SDouglas Gilbert 
977c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
978c65b1445SDouglas Gilbert 		return errsts;
979c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
980c65b1445SDouglas Gilbert 	if (power_cond) {
981c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
982c65b1445SDouglas Gilbert 			       	0);
983c65b1445SDouglas Gilbert 		return check_condition_result;
984c65b1445SDouglas Gilbert 	}
985c65b1445SDouglas Gilbert 	start = cmd[4] & 1;
986c65b1445SDouglas Gilbert 	if (start == devip->stopped)
987c65b1445SDouglas Gilbert 		devip->stopped = !start;
988c65b1445SDouglas Gilbert 	return 0;
989c65b1445SDouglas Gilbert }
990c65b1445SDouglas Gilbert 
99128898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
99228898873SFUJITA Tomonori {
99328898873SFUJITA Tomonori 	if (scsi_debug_virtual_gb > 0)
9945447ed6cSDouglas Gilbert 		return (sector_t)scsi_debug_virtual_gb *
9955447ed6cSDouglas Gilbert 			(1073741824 / scsi_debug_sector_size);
99628898873SFUJITA Tomonori 	else
99728898873SFUJITA Tomonori 		return sdebug_store_sectors;
99828898873SFUJITA Tomonori }
99928898873SFUJITA Tomonori 
10001da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
10011da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp,
10021da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
10031da177e4SLinus Torvalds {
10041da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1005c65b1445SDouglas Gilbert 	unsigned int capac;
10061da177e4SLinus Torvalds 	int errsts;
10071da177e4SLinus Torvalds 
1008c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
10091da177e4SLinus Torvalds 		return errsts;
1010c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
101128898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
10121da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1013c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1014c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
10151da177e4SLinus Torvalds 		arr[0] = (capac >> 24);
10161da177e4SLinus Torvalds 		arr[1] = (capac >> 16) & 0xff;
10171da177e4SLinus Torvalds 		arr[2] = (capac >> 8) & 0xff;
10181da177e4SLinus Torvalds 		arr[3] = capac & 0xff;
1019c65b1445SDouglas Gilbert 	} else {
1020c65b1445SDouglas Gilbert 		arr[0] = 0xff;
1021c65b1445SDouglas Gilbert 		arr[1] = 0xff;
1022c65b1445SDouglas Gilbert 		arr[2] = 0xff;
1023c65b1445SDouglas Gilbert 		arr[3] = 0xff;
1024c65b1445SDouglas Gilbert 	}
1025597136abSMartin K. Petersen 	arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
1026597136abSMartin K. Petersen 	arr[7] = scsi_debug_sector_size & 0xff;
10271da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
10281da177e4SLinus Torvalds }
10291da177e4SLinus Torvalds 
1030c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1031c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp,
1032c65b1445SDouglas Gilbert 			  struct sdebug_dev_info * devip)
1033c65b1445SDouglas Gilbert {
1034c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1035c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1036c65b1445SDouglas Gilbert 	unsigned long long capac;
1037c65b1445SDouglas Gilbert 	int errsts, k, alloc_len;
1038c65b1445SDouglas Gilbert 
1039c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1040c65b1445SDouglas Gilbert 		return errsts;
1041c65b1445SDouglas Gilbert 	alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1042c65b1445SDouglas Gilbert 		     + cmd[13]);
1043c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
104428898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1045c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1046c65b1445SDouglas Gilbert 	capac = sdebug_capacity - 1;
1047c65b1445SDouglas Gilbert 	for (k = 0; k < 8; ++k, capac >>= 8)
1048c65b1445SDouglas Gilbert 		arr[7 - k] = capac & 0xff;
1049597136abSMartin K. Petersen 	arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
1050597136abSMartin K. Petersen 	arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
1051597136abSMartin K. Petersen 	arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
1052597136abSMartin K. Petersen 	arr[11] = scsi_debug_sector_size & 0xff;
1053ea61fca5SMartin K. Petersen 	arr[13] = scsi_debug_physblk_exp & 0xf;
1054ea61fca5SMartin K. Petersen 	arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
105544d92694SMartin K. Petersen 
10566014759cSMartin K. Petersen 	if (scsi_debug_tpu || scsi_debug_tpws)
105744d92694SMartin K. Petersen 		arr[14] |= 0x80; /* TPE */
105844d92694SMartin K. Petersen 
1059ea61fca5SMartin K. Petersen 	arr[15] = scsi_debug_lowest_aligned & 0xff;
1060c6a44287SMartin K. Petersen 
1061c6a44287SMartin K. Petersen 	if (scsi_debug_dif) {
1062c6a44287SMartin K. Petersen 		arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
1063c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1064c6a44287SMartin K. Petersen 	}
1065c6a44287SMartin K. Petersen 
1066c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1067c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1068c65b1445SDouglas Gilbert }
1069c65b1445SDouglas Gilbert 
10705a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
10715a09e398SHannes Reinecke 
10725a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp,
10735a09e398SHannes Reinecke 			      struct sdebug_dev_info * devip)
10745a09e398SHannes Reinecke {
10755a09e398SHannes Reinecke 	unsigned char *cmd = (unsigned char *)scp->cmnd;
10765a09e398SHannes Reinecke 	unsigned char * arr;
10775a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
10785a09e398SHannes Reinecke 	int n, ret, alen, rlen;
10795a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
10805a09e398SHannes Reinecke 
10815a09e398SHannes Reinecke 	alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
10825a09e398SHannes Reinecke 		+ cmd[9]);
10835a09e398SHannes Reinecke 
10846f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
10856f3cbf55SDouglas Gilbert 	if (! arr)
10866f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
10875a09e398SHannes Reinecke 	/*
10885a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
10895a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
10905a09e398SHannes Reinecke 	 * So we create two port groups with one port each
10915a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
10925a09e398SHannes Reinecke 	 */
10935a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
10945a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
10955a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
10965a09e398SHannes Reinecke 	    (devip->channel & 0x7f);
10975a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
10985a09e398SHannes Reinecke 	    (devip->channel & 0x7f) + 0x80;
10995a09e398SHannes Reinecke 
11005a09e398SHannes Reinecke 	/*
11015a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
11025a09e398SHannes Reinecke 	 */
11035a09e398SHannes Reinecke 	n = 4;
11045a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno) {
11055a09e398SHannes Reinecke 	    arr[n++] = host_no % 3; /* Asymm access state */
11065a09e398SHannes Reinecke 	    arr[n++] = 0x0F; /* claim: all states are supported */
11075a09e398SHannes Reinecke 	} else {
11085a09e398SHannes Reinecke 	    arr[n++] = 0x0; /* Active/Optimized path */
11095a09e398SHannes Reinecke 	    arr[n++] = 0x01; /* claim: only support active/optimized paths */
11105a09e398SHannes Reinecke 	}
11115a09e398SHannes Reinecke 	arr[n++] = (port_group_a >> 8) & 0xff;
11125a09e398SHannes Reinecke 	arr[n++] = port_group_a & 0xff;
11135a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11145a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
11155a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
11165a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
11175a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11185a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11195a09e398SHannes Reinecke 	arr[n++] = (port_a >> 8) & 0xff;
11205a09e398SHannes Reinecke 	arr[n++] = port_a & 0xff;
11215a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
11225a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
11235a09e398SHannes Reinecke 	arr[n++] = (port_group_b >> 8) & 0xff;
11245a09e398SHannes Reinecke 	arr[n++] = port_group_b & 0xff;
11255a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11265a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
11275a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
11285a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
11295a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11305a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11315a09e398SHannes Reinecke 	arr[n++] = (port_b >> 8) & 0xff;
11325a09e398SHannes Reinecke 	arr[n++] = port_b & 0xff;
11335a09e398SHannes Reinecke 
11345a09e398SHannes Reinecke 	rlen = n - 4;
11355a09e398SHannes Reinecke 	arr[0] = (rlen >> 24) & 0xff;
11365a09e398SHannes Reinecke 	arr[1] = (rlen >> 16) & 0xff;
11375a09e398SHannes Reinecke 	arr[2] = (rlen >> 8) & 0xff;
11385a09e398SHannes Reinecke 	arr[3] = rlen & 0xff;
11395a09e398SHannes Reinecke 
11405a09e398SHannes Reinecke 	/*
11415a09e398SHannes Reinecke 	 * Return the smallest value of either
11425a09e398SHannes Reinecke 	 * - The allocated length
11435a09e398SHannes Reinecke 	 * - The constructed command length
11445a09e398SHannes Reinecke 	 * - The maximum array size
11455a09e398SHannes Reinecke 	 */
11465a09e398SHannes Reinecke 	rlen = min(alen,n);
11475a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
11485a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
11495a09e398SHannes Reinecke 	kfree(arr);
11505a09e398SHannes Reinecke 	return ret;
11515a09e398SHannes Reinecke }
11525a09e398SHannes Reinecke 
11531da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
11541da177e4SLinus Torvalds 
11551da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
11561da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
11571da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
11581da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
11591da177e4SLinus Torvalds 
11601da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
11611da177e4SLinus Torvalds 	if (1 == pcontrol)
11621da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
11631da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
11641da177e4SLinus Torvalds }
11651da177e4SLinus Torvalds 
11661da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
11671da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
11681da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
11691da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
11701da177e4SLinus Torvalds 
11711da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
11721da177e4SLinus Torvalds 	if (1 == pcontrol)
11731da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
11741da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
11751da177e4SLinus Torvalds }
11761da177e4SLinus Torvalds 
11771da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target)
11781da177e4SLinus Torvalds {       /* Format device page for mode_sense */
11791da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
11801da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
11811da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
11821da177e4SLinus Torvalds 
11831da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
11841da177e4SLinus Torvalds 	p[10] = (sdebug_sectors_per >> 8) & 0xff;
11851da177e4SLinus Torvalds 	p[11] = sdebug_sectors_per & 0xff;
1186597136abSMartin K. Petersen 	p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1187597136abSMartin K. Petersen 	p[13] = scsi_debug_sector_size & 0xff;
11881da177e4SLinus Torvalds 	if (DEV_REMOVEABLE(target))
11891da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
11901da177e4SLinus Torvalds 	if (1 == pcontrol)
11911da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
11921da177e4SLinus Torvalds 	return sizeof(format_pg);
11931da177e4SLinus Torvalds }
11941da177e4SLinus Torvalds 
11951da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
11961da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
11971da177e4SLinus Torvalds 	unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
11981da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
11991da177e4SLinus Torvalds 
12001da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
12011da177e4SLinus Torvalds 	if (1 == pcontrol)
12021da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(caching_pg) - 2);
12031da177e4SLinus Torvalds 	return sizeof(caching_pg);
12041da177e4SLinus Torvalds }
12051da177e4SLinus Torvalds 
12061da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
12071da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
1208c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1209c65b1445SDouglas Gilbert 				        0, 0, 0, 0};
1210c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
12111da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
12121da177e4SLinus Torvalds 
12131da177e4SLinus Torvalds 	if (scsi_debug_dsense)
12141da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
1215c65b1445SDouglas Gilbert 	else
1216c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
1217c6a44287SMartin K. Petersen 
1218c6a44287SMartin K. Petersen 	if (scsi_debug_ato)
1219c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1220c6a44287SMartin K. Petersen 
12211da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
12221da177e4SLinus Torvalds 	if (1 == pcontrol)
1223c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1224c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1225c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
12261da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
12271da177e4SLinus Torvalds }
12281da177e4SLinus Torvalds 
1229c65b1445SDouglas Gilbert 
12301da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
12311da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
1232c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
12331da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
1234c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1235c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
1236c65b1445SDouglas Gilbert 
12371da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
12381da177e4SLinus Torvalds 	if (1 == pcontrol)
1239c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1240c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1241c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
12421da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
12431da177e4SLinus Torvalds }
12441da177e4SLinus Torvalds 
1245c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1246c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
1247c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1248c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1249c65b1445SDouglas Gilbert 
1250c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1251c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1252c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1253c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
1254c65b1445SDouglas Gilbert }
1255c65b1445SDouglas Gilbert 
1256c65b1445SDouglas Gilbert 
1257c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1258c65b1445SDouglas Gilbert 			      int target_dev_id)
1259c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
1260c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1261c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1262c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1263c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1264c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
1265c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1266c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1267c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1268c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1269c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1270c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
1271c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1272c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1273c65b1445SDouglas Gilbert 		};
1274c65b1445SDouglas Gilbert 	int port_a, port_b;
1275c65b1445SDouglas Gilbert 
1276c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1277c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1278c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1279c65b1445SDouglas Gilbert 	p[20] = (port_a >> 24);
1280c65b1445SDouglas Gilbert 	p[21] = (port_a >> 16) & 0xff;
1281c65b1445SDouglas Gilbert 	p[22] = (port_a >> 8) & 0xff;
1282c65b1445SDouglas Gilbert 	p[23] = port_a & 0xff;
1283c65b1445SDouglas Gilbert 	p[48 + 20] = (port_b >> 24);
1284c65b1445SDouglas Gilbert 	p[48 + 21] = (port_b >> 16) & 0xff;
1285c65b1445SDouglas Gilbert 	p[48 + 22] = (port_b >> 8) & 0xff;
1286c65b1445SDouglas Gilbert 	p[48 + 23] = port_b & 0xff;
1287c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1288c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1289c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
1290c65b1445SDouglas Gilbert }
1291c65b1445SDouglas Gilbert 
1292c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1293c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
1294c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1295c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1296c65b1445SDouglas Gilbert 		};
1297c65b1445SDouglas Gilbert 
1298c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1299c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1300c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1301c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
1302c65b1445SDouglas Gilbert }
1303c65b1445SDouglas Gilbert 
13041da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
13051da177e4SLinus Torvalds 
13061da177e4SLinus Torvalds static int resp_mode_sense(struct scsi_cmnd * scp, int target,
13071da177e4SLinus Torvalds 			   struct sdebug_dev_info * devip)
13081da177e4SLinus Torvalds {
130923183910SDouglas Gilbert 	unsigned char dbd, llbaa;
131023183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
13111da177e4SLinus Torvalds 	unsigned char dev_spec;
131223183910SDouglas Gilbert 	int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
13131da177e4SLinus Torvalds 	unsigned char * ap;
13141da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
13151da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
13161da177e4SLinus Torvalds 
1317c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
13181da177e4SLinus Torvalds 		return errsts;
131923183910SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);
13201da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
13211da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
13221da177e4SLinus Torvalds 	subpcode = cmd[3];
13231da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
132423183910SDouglas Gilbert 	llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
132523183910SDouglas Gilbert 	if ((0 == scsi_debug_ptype) && (0 == dbd))
132623183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
132723183910SDouglas Gilbert 	else
132823183910SDouglas Gilbert 		bd_len = 0;
13291da177e4SLinus Torvalds 	alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
13301da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
13311da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
13321da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
13331da177e4SLinus Torvalds 			       	0);
13341da177e4SLinus Torvalds 		return check_condition_result;
13351da177e4SLinus Torvalds 	}
1336c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1337c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
133823183910SDouglas Gilbert 	/* set DPOFUA bit for disks */
133923183910SDouglas Gilbert 	if (0 == scsi_debug_ptype)
134023183910SDouglas Gilbert 		dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
134123183910SDouglas Gilbert 	else
134223183910SDouglas Gilbert 		dev_spec = 0x0;
13431da177e4SLinus Torvalds 	if (msense_6) {
13441da177e4SLinus Torvalds 		arr[2] = dev_spec;
134523183910SDouglas Gilbert 		arr[3] = bd_len;
13461da177e4SLinus Torvalds 		offset = 4;
13471da177e4SLinus Torvalds 	} else {
13481da177e4SLinus Torvalds 		arr[3] = dev_spec;
134923183910SDouglas Gilbert 		if (16 == bd_len)
135023183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
135123183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
13521da177e4SLinus Torvalds 		offset = 8;
13531da177e4SLinus Torvalds 	}
13541da177e4SLinus Torvalds 	ap = arr + offset;
135528898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
135628898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
135728898873SFUJITA Tomonori 
135823183910SDouglas Gilbert 	if (8 == bd_len) {
135923183910SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe) {
136023183910SDouglas Gilbert 			ap[0] = 0xff;
136123183910SDouglas Gilbert 			ap[1] = 0xff;
136223183910SDouglas Gilbert 			ap[2] = 0xff;
136323183910SDouglas Gilbert 			ap[3] = 0xff;
136423183910SDouglas Gilbert 		} else {
136523183910SDouglas Gilbert 			ap[0] = (sdebug_capacity >> 24) & 0xff;
136623183910SDouglas Gilbert 			ap[1] = (sdebug_capacity >> 16) & 0xff;
136723183910SDouglas Gilbert 			ap[2] = (sdebug_capacity >> 8) & 0xff;
136823183910SDouglas Gilbert 			ap[3] = sdebug_capacity & 0xff;
136923183910SDouglas Gilbert 		}
1370597136abSMartin K. Petersen 		ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1371597136abSMartin K. Petersen 		ap[7] = scsi_debug_sector_size & 0xff;
137223183910SDouglas Gilbert 		offset += bd_len;
137323183910SDouglas Gilbert 		ap = arr + offset;
137423183910SDouglas Gilbert 	} else if (16 == bd_len) {
137523183910SDouglas Gilbert 		unsigned long long capac = sdebug_capacity;
137623183910SDouglas Gilbert 
137723183910SDouglas Gilbert         	for (k = 0; k < 8; ++k, capac >>= 8)
137823183910SDouglas Gilbert                 	ap[7 - k] = capac & 0xff;
1379597136abSMartin K. Petersen 		ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1380597136abSMartin K. Petersen 		ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1381597136abSMartin K. Petersen 		ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1382597136abSMartin K. Petersen 		ap[15] = scsi_debug_sector_size & 0xff;
138323183910SDouglas Gilbert 		offset += bd_len;
138423183910SDouglas Gilbert 		ap = arr + offset;
138523183910SDouglas Gilbert 	}
13861da177e4SLinus Torvalds 
1387c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1388c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
13891da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
13901da177e4SLinus Torvalds 			       	0);
13911da177e4SLinus Torvalds 		return check_condition_result;
13921da177e4SLinus Torvalds 	}
13931da177e4SLinus Torvalds 	switch (pcode) {
13941da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
13951da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
13961da177e4SLinus Torvalds 		offset += len;
13971da177e4SLinus Torvalds 		break;
13981da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
13991da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
14001da177e4SLinus Torvalds 		offset += len;
14011da177e4SLinus Torvalds 		break;
14021da177e4SLinus Torvalds         case 0x3:       /* Format device page, direct access */
14031da177e4SLinus Torvalds                 len = resp_format_pg(ap, pcontrol, target);
14041da177e4SLinus Torvalds                 offset += len;
14051da177e4SLinus Torvalds                 break;
14061da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
14071da177e4SLinus Torvalds 		len = resp_caching_pg(ap, pcontrol, target);
14081da177e4SLinus Torvalds 		offset += len;
14091da177e4SLinus Torvalds 		break;
14101da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
14111da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
14121da177e4SLinus Torvalds 		offset += len;
14131da177e4SLinus Torvalds 		break;
1414c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
1415c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
1416c65b1445SDouglas Gilbert 		        mk_sense_buffer(devip, ILLEGAL_REQUEST,
1417c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1418c65b1445SDouglas Gilbert 			return check_condition_result;
1419c65b1445SDouglas Gilbert 	        }
1420c65b1445SDouglas Gilbert 		len = 0;
1421c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
1422c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1423c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
1424c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1425c65b1445SDouglas Gilbert 						  target_dev_id);
1426c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
1427c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
1428c65b1445SDouglas Gilbert 		offset += len;
1429c65b1445SDouglas Gilbert 		break;
14301da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
14311da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
14321da177e4SLinus Torvalds 		offset += len;
14331da177e4SLinus Torvalds 		break;
14341da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
1435c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
14361da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
14371da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
14381da177e4SLinus Torvalds 			len += resp_format_pg(ap + len, pcontrol, target);
14391da177e4SLinus Torvalds 			len += resp_caching_pg(ap + len, pcontrol, target);
14401da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1441c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1442c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
1443c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1444c65b1445SDouglas Gilbert 						  target, target_dev_id);
1445c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
1446c65b1445SDouglas Gilbert 			}
14471da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
1448c65b1445SDouglas Gilbert 		} else {
1449c65b1445SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
1450c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1451c65b1445SDouglas Gilbert 			return check_condition_result;
1452c65b1445SDouglas Gilbert                 }
14531da177e4SLinus Torvalds 		offset += len;
14541da177e4SLinus Torvalds 		break;
14551da177e4SLinus Torvalds 	default:
14561da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
14571da177e4SLinus Torvalds 			       	0);
14581da177e4SLinus Torvalds 		return check_condition_result;
14591da177e4SLinus Torvalds 	}
14601da177e4SLinus Torvalds 	if (msense_6)
14611da177e4SLinus Torvalds 		arr[0] = offset - 1;
14621da177e4SLinus Torvalds 	else {
14631da177e4SLinus Torvalds 		arr[0] = ((offset - 2) >> 8) & 0xff;
14641da177e4SLinus Torvalds 		arr[1] = (offset - 2) & 0xff;
14651da177e4SLinus Torvalds 	}
14661da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
14671da177e4SLinus Torvalds }
14681da177e4SLinus Torvalds 
1469c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
1470c65b1445SDouglas Gilbert 
1471c65b1445SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1472c65b1445SDouglas Gilbert 			    struct sdebug_dev_info * devip)
1473c65b1445SDouglas Gilbert {
1474c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1475c65b1445SDouglas Gilbert 	int param_len, res, errsts, mpage;
1476c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1477c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1478c65b1445SDouglas Gilbert 
1479c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1480c65b1445SDouglas Gilbert 		return errsts;
1481c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1482c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
1483c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
1484c65b1445SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1485c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1486c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1487c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
1488c65b1445SDouglas Gilbert 		return check_condition_result;
1489c65b1445SDouglas Gilbert 	}
1490c65b1445SDouglas Gilbert         res = fetch_to_dev_buffer(scp, arr, param_len);
1491c65b1445SDouglas Gilbert         if (-1 == res)
1492c65b1445SDouglas Gilbert                 return (DID_ERROR << 16);
1493c65b1445SDouglas Gilbert         else if ((res < param_len) &&
1494c65b1445SDouglas Gilbert                  (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1495c65b1445SDouglas Gilbert                 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1496c65b1445SDouglas Gilbert                        " IO sent=%d bytes\n", param_len, res);
1497c65b1445SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1498c65b1445SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
149923183910SDouglas Gilbert 	if (md_len > 2) {
1500c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1501c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_PARAM_LIST, 0);
1502c65b1445SDouglas Gilbert 		return check_condition_result;
1503c65b1445SDouglas Gilbert 	}
1504c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
1505c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
1506c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
1507c65b1445SDouglas Gilbert 	if (ps) {
1508c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1509c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_PARAM_LIST, 0);
1510c65b1445SDouglas Gilbert 		return check_condition_result;
1511c65b1445SDouglas Gilbert 	}
1512c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
1513c65b1445SDouglas Gilbert 	pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1514c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
1515c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
1516c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1517c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
1518c65b1445SDouglas Gilbert 		return check_condition_result;
1519c65b1445SDouglas Gilbert 	}
1520c65b1445SDouglas Gilbert 	switch (mpage) {
1521c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
1522c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
1523c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
1524c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
1525c65b1445SDouglas Gilbert 			scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1526c65b1445SDouglas Gilbert 			return 0;
1527c65b1445SDouglas Gilbert 		}
1528c65b1445SDouglas Gilbert 		break;
1529c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
1530c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
1531c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
1532c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
1533c65b1445SDouglas Gilbert 			return 0;
1534c65b1445SDouglas Gilbert 		}
1535c65b1445SDouglas Gilbert 		break;
1536c65b1445SDouglas Gilbert 	default:
1537c65b1445SDouglas Gilbert 		break;
1538c65b1445SDouglas Gilbert 	}
1539c65b1445SDouglas Gilbert 	mk_sense_buffer(devip, ILLEGAL_REQUEST,
1540c65b1445SDouglas Gilbert 			INVALID_FIELD_IN_PARAM_LIST, 0);
1541c65b1445SDouglas Gilbert 	return check_condition_result;
1542c65b1445SDouglas Gilbert }
1543c65b1445SDouglas Gilbert 
1544c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr)
1545c65b1445SDouglas Gilbert {
1546c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1547c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
1548c65b1445SDouglas Gilbert 		};
1549c65b1445SDouglas Gilbert 
1550c65b1445SDouglas Gilbert         memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1551c65b1445SDouglas Gilbert         return sizeof(temp_l_pg);
1552c65b1445SDouglas Gilbert }
1553c65b1445SDouglas Gilbert 
1554c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr)
1555c65b1445SDouglas Gilbert {
1556c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1557c65b1445SDouglas Gilbert 		};
1558c65b1445SDouglas Gilbert 
1559c65b1445SDouglas Gilbert         memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1560c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
1561c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
1562c65b1445SDouglas Gilbert 		arr[5] = 0xff;
1563c65b1445SDouglas Gilbert 	}
1564c65b1445SDouglas Gilbert         return sizeof(ie_l_pg);
1565c65b1445SDouglas Gilbert }
1566c65b1445SDouglas Gilbert 
1567c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
1568c65b1445SDouglas Gilbert 
1569c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp,
1570c65b1445SDouglas Gilbert                           struct sdebug_dev_info * devip)
1571c65b1445SDouglas Gilbert {
157223183910SDouglas Gilbert 	int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
1573c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1574c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1575c65b1445SDouglas Gilbert 
1576c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1577c65b1445SDouglas Gilbert 		return errsts;
1578c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1579c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
1580c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
1581c65b1445SDouglas Gilbert 	if (ppc || sp) {
1582c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1583c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
1584c65b1445SDouglas Gilbert 		return check_condition_result;
1585c65b1445SDouglas Gilbert 	}
1586c65b1445SDouglas Gilbert 	pcontrol = (cmd[2] & 0xc0) >> 6;
1587c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
158823183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
1589c65b1445SDouglas Gilbert 	alloc_len = (cmd[7] << 8) + cmd[8];
1590c65b1445SDouglas Gilbert 	arr[0] = pcode;
159123183910SDouglas Gilbert 	if (0 == subpcode) {
1592c65b1445SDouglas Gilbert 		switch (pcode) {
1593c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
1594c65b1445SDouglas Gilbert 			n = 4;
1595c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
1596c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
1597c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
1598c65b1445SDouglas Gilbert 			arr[3] = n - 4;
1599c65b1445SDouglas Gilbert 			break;
1600c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
1601c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
1602c65b1445SDouglas Gilbert 			break;
1603c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
1604c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
1605c65b1445SDouglas Gilbert 			break;
1606c65b1445SDouglas Gilbert 		default:
1607c65b1445SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
1608c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1609c65b1445SDouglas Gilbert 			return check_condition_result;
1610c65b1445SDouglas Gilbert 		}
161123183910SDouglas Gilbert 	} else if (0xff == subpcode) {
161223183910SDouglas Gilbert 		arr[0] |= 0x40;
161323183910SDouglas Gilbert 		arr[1] = subpcode;
161423183910SDouglas Gilbert 		switch (pcode) {
161523183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
161623183910SDouglas Gilbert 			n = 4;
161723183910SDouglas Gilbert 			arr[n++] = 0x0;
161823183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
161923183910SDouglas Gilbert 			arr[n++] = 0x0;
162023183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
162123183910SDouglas Gilbert 			arr[n++] = 0xd;
162223183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
162323183910SDouglas Gilbert 			arr[n++] = 0x2f;
162423183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
162523183910SDouglas Gilbert 			arr[3] = n - 4;
162623183910SDouglas Gilbert 			break;
162723183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
162823183910SDouglas Gilbert 			n = 4;
162923183910SDouglas Gilbert 			arr[n++] = 0xd;
163023183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
163123183910SDouglas Gilbert 			arr[3] = n - 4;
163223183910SDouglas Gilbert 			break;
163323183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
163423183910SDouglas Gilbert 			n = 4;
163523183910SDouglas Gilbert 			arr[n++] = 0x2f;
163623183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
163723183910SDouglas Gilbert 			arr[3] = n - 4;
163823183910SDouglas Gilbert 			break;
163923183910SDouglas Gilbert 		default:
164023183910SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
164123183910SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
164223183910SDouglas Gilbert 			return check_condition_result;
164323183910SDouglas Gilbert 		}
164423183910SDouglas Gilbert 	} else {
164523183910SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
164623183910SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
164723183910SDouglas Gilbert 		return check_condition_result;
164823183910SDouglas Gilbert 	}
1649c65b1445SDouglas Gilbert 	len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1650c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1651c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
1652c65b1445SDouglas Gilbert }
1653c65b1445SDouglas Gilbert 
165419789100SFUJITA Tomonori static int check_device_access_params(struct sdebug_dev_info *devi,
165519789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
16561da177e4SLinus Torvalds {
1657c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
165819789100SFUJITA Tomonori 		mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
16591da177e4SLinus Torvalds 		return check_condition_result;
16601da177e4SLinus Torvalds 	}
1661c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
1662c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
166319789100SFUJITA Tomonori 		mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
1664c65b1445SDouglas Gilbert 		return check_condition_result;
1665c65b1445SDouglas Gilbert 	}
166619789100SFUJITA Tomonori 	return 0;
166719789100SFUJITA Tomonori }
166819789100SFUJITA Tomonori 
166919789100SFUJITA Tomonori static int do_device_access(struct scsi_cmnd *scmd,
167019789100SFUJITA Tomonori 			    struct sdebug_dev_info *devi,
167119789100SFUJITA Tomonori 			    unsigned long long lba, unsigned int num, int write)
167219789100SFUJITA Tomonori {
167319789100SFUJITA Tomonori 	int ret;
167419789100SFUJITA Tomonori 	unsigned int block, rest = 0;
167519789100SFUJITA Tomonori 	int (*func)(struct scsi_cmnd *, unsigned char *, int);
167619789100SFUJITA Tomonori 
167719789100SFUJITA Tomonori 	func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
167819789100SFUJITA Tomonori 
167919789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
168019789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
168119789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
168219789100SFUJITA Tomonori 
1683597136abSMartin K. Petersen 	ret = func(scmd, fake_storep + (block * scsi_debug_sector_size),
1684597136abSMartin K. Petersen 		   (num - rest) * scsi_debug_sector_size);
168519789100SFUJITA Tomonori 	if (!ret && rest)
1686597136abSMartin K. Petersen 		ret = func(scmd, fake_storep, rest * scsi_debug_sector_size);
168719789100SFUJITA Tomonori 
168819789100SFUJITA Tomonori 	return ret;
168919789100SFUJITA Tomonori }
169019789100SFUJITA Tomonori 
1691c6a44287SMartin K. Petersen static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
1692395cef03SMartin K. Petersen 			    unsigned int sectors, u32 ei_lba)
1693c6a44287SMartin K. Petersen {
1694c6a44287SMartin K. Petersen 	unsigned int i, resid;
1695c6a44287SMartin K. Petersen 	struct scatterlist *psgl;
1696c6a44287SMartin K. Petersen 	struct sd_dif_tuple *sdt;
1697c6a44287SMartin K. Petersen 	sector_t sector;
1698c6a44287SMartin K. Petersen 	sector_t tmp_sec = start_sec;
1699c6a44287SMartin K. Petersen 	void *paddr;
1700c6a44287SMartin K. Petersen 
1701c6a44287SMartin K. Petersen 	start_sec = do_div(tmp_sec, sdebug_store_sectors);
1702c6a44287SMartin K. Petersen 
1703c6a44287SMartin K. Petersen 	sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec));
1704c6a44287SMartin K. Petersen 
1705c6a44287SMartin K. Petersen 	for (i = 0 ; i < sectors ; i++) {
1706c6a44287SMartin K. Petersen 		u16 csum;
1707c6a44287SMartin K. Petersen 
1708c6a44287SMartin K. Petersen 		if (sdt[i].app_tag == 0xffff)
1709c6a44287SMartin K. Petersen 			continue;
1710c6a44287SMartin K. Petersen 
1711c6a44287SMartin K. Petersen 		sector = start_sec + i;
1712c6a44287SMartin K. Petersen 
1713c6a44287SMartin K. Petersen 		switch (scsi_debug_guard) {
1714c6a44287SMartin K. Petersen 		case 1:
1715c6a44287SMartin K. Petersen 			csum = ip_compute_csum(fake_storep +
1716c6a44287SMartin K. Petersen 					       sector * scsi_debug_sector_size,
1717c6a44287SMartin K. Petersen 					       scsi_debug_sector_size);
1718c6a44287SMartin K. Petersen 			break;
1719c6a44287SMartin K. Petersen 		case 0:
1720c6a44287SMartin K. Petersen 			csum = crc_t10dif(fake_storep +
1721c6a44287SMartin K. Petersen 					  sector * scsi_debug_sector_size,
1722c6a44287SMartin K. Petersen 					  scsi_debug_sector_size);
1723c6a44287SMartin K. Petersen 			csum = cpu_to_be16(csum);
1724c6a44287SMartin K. Petersen 			break;
1725c6a44287SMartin K. Petersen 		default:
1726c6a44287SMartin K. Petersen 			BUG();
1727c6a44287SMartin K. Petersen 		}
1728c6a44287SMartin K. Petersen 
1729c6a44287SMartin K. Petersen 		if (sdt[i].guard_tag != csum) {
1730c6a44287SMartin K. Petersen 			printk(KERN_ERR "%s: GUARD check failed on sector %lu" \
1731c6a44287SMartin K. Petersen 			       " rcvd 0x%04x, data 0x%04x\n", __func__,
1732c6a44287SMartin K. Petersen 			       (unsigned long)sector,
1733c6a44287SMartin K. Petersen 			       be16_to_cpu(sdt[i].guard_tag),
1734c6a44287SMartin K. Petersen 			       be16_to_cpu(csum));
1735c6a44287SMartin K. Petersen 			dif_errors++;
1736c6a44287SMartin K. Petersen 			return 0x01;
1737c6a44287SMartin K. Petersen 		}
1738c6a44287SMartin K. Petersen 
1739395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
1740c6a44287SMartin K. Petersen 		    be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) {
1741c6a44287SMartin K. Petersen 			printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1742c6a44287SMartin K. Petersen 			       __func__, (unsigned long)sector);
1743c6a44287SMartin K. Petersen 			dif_errors++;
1744c6a44287SMartin K. Petersen 			return 0x03;
1745c6a44287SMartin K. Petersen 		}
1746395cef03SMartin K. Petersen 
1747395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1748395cef03SMartin K. Petersen 		    be32_to_cpu(sdt[i].ref_tag) != ei_lba) {
1749395cef03SMartin K. Petersen 			printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1750395cef03SMartin K. Petersen 			       __func__, (unsigned long)sector);
1751395cef03SMartin K. Petersen 			dif_errors++;
1752395cef03SMartin K. Petersen 			return 0x03;
1753395cef03SMartin K. Petersen 		}
1754395cef03SMartin K. Petersen 
1755395cef03SMartin K. Petersen 		ei_lba++;
1756c6a44287SMartin K. Petersen 	}
1757c6a44287SMartin K. Petersen 
1758c6a44287SMartin K. Petersen 	resid = sectors * 8; /* Bytes of protection data to copy into sgl */
1759c6a44287SMartin K. Petersen 	sector = start_sec;
1760c6a44287SMartin K. Petersen 
1761c6a44287SMartin K. Petersen 	scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
1762c6a44287SMartin K. Petersen 		int len = min(psgl->length, resid);
1763c6a44287SMartin K. Petersen 
1764c6a44287SMartin K. Petersen 		paddr = kmap_atomic(sg_page(psgl), KM_IRQ0) + psgl->offset;
1765c6a44287SMartin K. Petersen 		memcpy(paddr, dif_storep + dif_offset(sector), len);
1766c6a44287SMartin K. Petersen 
1767c6a44287SMartin K. Petersen 		sector += len >> 3;
1768c6a44287SMartin K. Petersen 		if (sector >= sdebug_store_sectors) {
1769c6a44287SMartin K. Petersen 			/* Force wrap */
1770c6a44287SMartin K. Petersen 			tmp_sec = sector;
1771c6a44287SMartin K. Petersen 			sector = do_div(tmp_sec, sdebug_store_sectors);
1772c6a44287SMartin K. Petersen 		}
1773c6a44287SMartin K. Petersen 		resid -= len;
1774c6a44287SMartin K. Petersen 		kunmap_atomic(paddr, KM_IRQ0);
1775c6a44287SMartin K. Petersen 	}
1776c6a44287SMartin K. Petersen 
1777c6a44287SMartin K. Petersen 	dix_reads++;
1778c6a44287SMartin K. Petersen 
1779c6a44287SMartin K. Petersen 	return 0;
1780c6a44287SMartin K. Petersen }
1781c6a44287SMartin K. Petersen 
178219789100SFUJITA Tomonori static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
1783395cef03SMartin K. Petersen 		     unsigned int num, struct sdebug_dev_info *devip,
1784395cef03SMartin K. Petersen 		     u32 ei_lba)
178519789100SFUJITA Tomonori {
178619789100SFUJITA Tomonori 	unsigned long iflags;
178719789100SFUJITA Tomonori 	int ret;
178819789100SFUJITA Tomonori 
178919789100SFUJITA Tomonori 	ret = check_device_access_params(devip, lba, num);
179019789100SFUJITA Tomonori 	if (ret)
179119789100SFUJITA Tomonori 		return ret;
179219789100SFUJITA Tomonori 
17931da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
1794c65b1445SDouglas Gilbert 	    (lba <= OPT_MEDIUM_ERR_ADDR) &&
1795c65b1445SDouglas Gilbert 	    ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1796c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
17971da177e4SLinus Torvalds 		mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
17981da177e4SLinus Torvalds 				0);
1799c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
1800c65b1445SDouglas Gilbert 		if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1801c65b1445SDouglas Gilbert 			devip->sense_buff[0] |= 0x80;	/* Valid bit */
1802c65b1445SDouglas Gilbert 			ret = OPT_MEDIUM_ERR_ADDR;
1803c65b1445SDouglas Gilbert 			devip->sense_buff[3] = (ret >> 24) & 0xff;
1804c65b1445SDouglas Gilbert 			devip->sense_buff[4] = (ret >> 16) & 0xff;
1805c65b1445SDouglas Gilbert 			devip->sense_buff[5] = (ret >> 8) & 0xff;
1806c65b1445SDouglas Gilbert 			devip->sense_buff[6] = ret & 0xff;
1807c65b1445SDouglas Gilbert 		}
1808a87e3a67SDouglas Gilbert 	        scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
18091da177e4SLinus Torvalds 		return check_condition_result;
18101da177e4SLinus Torvalds 	}
1811c6a44287SMartin K. Petersen 
1812c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
1813c6a44287SMartin K. Petersen 	if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
1814395cef03SMartin K. Petersen 		int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
1815c6a44287SMartin K. Petersen 
1816c6a44287SMartin K. Petersen 		if (prot_ret) {
1817c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
1818c6a44287SMartin K. Petersen 			return illegal_condition_result;
1819c6a44287SMartin K. Petersen 		}
1820c6a44287SMartin K. Petersen 	}
1821c6a44287SMartin K. Petersen 
18221da177e4SLinus Torvalds 	read_lock_irqsave(&atomic_rw, iflags);
182319789100SFUJITA Tomonori 	ret = do_device_access(SCpnt, devip, lba, num, 0);
18241da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
18251da177e4SLinus Torvalds 	return ret;
18261da177e4SLinus Torvalds }
18271da177e4SLinus Torvalds 
1828c6a44287SMartin K. Petersen void dump_sector(unsigned char *buf, int len)
1829c6a44287SMartin K. Petersen {
1830c6a44287SMartin K. Petersen 	int i, j;
1831c6a44287SMartin K. Petersen 
1832c6a44287SMartin K. Petersen 	printk(KERN_ERR ">>> Sector Dump <<<\n");
1833c6a44287SMartin K. Petersen 
1834c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
1835c6a44287SMartin K. Petersen 		printk(KERN_ERR "%04d: ", i);
1836c6a44287SMartin K. Petersen 
1837c6a44287SMartin K. Petersen 		for (j = 0 ; j < 16 ; j++) {
1838c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
1839c6a44287SMartin K. Petersen 			if (c >= 0x20 && c < 0x7e)
1840c6a44287SMartin K. Petersen 				printk(" %c ", buf[i+j]);
1841c6a44287SMartin K. Petersen 			else
1842c6a44287SMartin K. Petersen 				printk("%02x ", buf[i+j]);
1843c6a44287SMartin K. Petersen 		}
1844c6a44287SMartin K. Petersen 
1845c6a44287SMartin K. Petersen 		printk("\n");
1846c6a44287SMartin K. Petersen 	}
1847c6a44287SMartin K. Petersen }
1848c6a44287SMartin K. Petersen 
1849c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
1850395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
1851c6a44287SMartin K. Petersen {
1852c6a44287SMartin K. Petersen 	int i, j, ret;
1853c6a44287SMartin K. Petersen 	struct sd_dif_tuple *sdt;
1854c6a44287SMartin K. Petersen 	struct scatterlist *dsgl = scsi_sglist(SCpnt);
1855c6a44287SMartin K. Petersen 	struct scatterlist *psgl = scsi_prot_sglist(SCpnt);
1856c6a44287SMartin K. Petersen 	void *daddr, *paddr;
1857c6a44287SMartin K. Petersen 	sector_t tmp_sec = start_sec;
1858c6a44287SMartin K. Petersen 	sector_t sector;
1859c6a44287SMartin K. Petersen 	int ppage_offset;
1860c6a44287SMartin K. Petersen 	unsigned short csum;
1861c6a44287SMartin K. Petersen 
1862c6a44287SMartin K. Petersen 	sector = do_div(tmp_sec, sdebug_store_sectors);
1863c6a44287SMartin K. Petersen 
1864c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
1865c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
1866c6a44287SMartin K. Petersen 
1867c6a44287SMartin K. Petersen 	paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) + psgl->offset;
1868c6a44287SMartin K. Petersen 	ppage_offset = 0;
1869c6a44287SMartin K. Petersen 
1870c6a44287SMartin K. Petersen 	/* For each data page */
1871c6a44287SMartin K. Petersen 	scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
1872c6a44287SMartin K. Petersen 		daddr = kmap_atomic(sg_page(dsgl), KM_IRQ0) + dsgl->offset;
1873c6a44287SMartin K. Petersen 
1874c6a44287SMartin K. Petersen 		/* For each sector-sized chunk in data page */
1875c6a44287SMartin K. Petersen 		for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) {
1876c6a44287SMartin K. Petersen 
1877c6a44287SMartin K. Petersen 			/* If we're at the end of the current
1878c6a44287SMartin K. Petersen 			 * protection page advance to the next one
1879c6a44287SMartin K. Petersen 			 */
1880c6a44287SMartin K. Petersen 			if (ppage_offset >= psgl->length) {
1881c6a44287SMartin K. Petersen 				kunmap_atomic(paddr, KM_IRQ1);
1882c6a44287SMartin K. Petersen 				psgl = sg_next(psgl);
1883c6a44287SMartin K. Petersen 				BUG_ON(psgl == NULL);
1884c6a44287SMartin K. Petersen 				paddr = kmap_atomic(sg_page(psgl), KM_IRQ1)
1885c6a44287SMartin K. Petersen 					+ psgl->offset;
1886c6a44287SMartin K. Petersen 				ppage_offset = 0;
1887c6a44287SMartin K. Petersen 			}
1888c6a44287SMartin K. Petersen 
1889c6a44287SMartin K. Petersen 			sdt = paddr + ppage_offset;
1890c6a44287SMartin K. Petersen 
1891c6a44287SMartin K. Petersen 			switch (scsi_debug_guard) {
1892c6a44287SMartin K. Petersen 			case 1:
1893c6a44287SMartin K. Petersen 				csum = ip_compute_csum(daddr,
1894c6a44287SMartin K. Petersen 						       scsi_debug_sector_size);
1895c6a44287SMartin K. Petersen 				break;
1896c6a44287SMartin K. Petersen 			case 0:
1897c6a44287SMartin K. Petersen 				csum = cpu_to_be16(crc_t10dif(daddr,
1898c6a44287SMartin K. Petersen 						      scsi_debug_sector_size));
1899c6a44287SMartin K. Petersen 				break;
1900c6a44287SMartin K. Petersen 			default:
1901c6a44287SMartin K. Petersen 				BUG();
1902c6a44287SMartin K. Petersen 				ret = 0;
1903c6a44287SMartin K. Petersen 				goto out;
1904c6a44287SMartin K. Petersen 			}
1905c6a44287SMartin K. Petersen 
1906c6a44287SMartin K. Petersen 			if (sdt->guard_tag != csum) {
1907c6a44287SMartin K. Petersen 				printk(KERN_ERR
1908c6a44287SMartin K. Petersen 				       "%s: GUARD check failed on sector %lu " \
1909c6a44287SMartin K. Petersen 				       "rcvd 0x%04x, calculated 0x%04x\n",
1910c6a44287SMartin K. Petersen 				       __func__, (unsigned long)sector,
1911c6a44287SMartin K. Petersen 				       be16_to_cpu(sdt->guard_tag),
1912c6a44287SMartin K. Petersen 				       be16_to_cpu(csum));
1913c6a44287SMartin K. Petersen 				ret = 0x01;
1914c6a44287SMartin K. Petersen 				dump_sector(daddr, scsi_debug_sector_size);
1915c6a44287SMartin K. Petersen 				goto out;
1916c6a44287SMartin K. Petersen 			}
1917c6a44287SMartin K. Petersen 
1918395cef03SMartin K. Petersen 			if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
1919c6a44287SMartin K. Petersen 			    be32_to_cpu(sdt->ref_tag)
1920c6a44287SMartin K. Petersen 			    != (start_sec & 0xffffffff)) {
1921c6a44287SMartin K. Petersen 				printk(KERN_ERR
1922c6a44287SMartin K. Petersen 				       "%s: REF check failed on sector %lu\n",
1923c6a44287SMartin K. Petersen 				       __func__, (unsigned long)sector);
1924c6a44287SMartin K. Petersen 				ret = 0x03;
1925c6a44287SMartin K. Petersen 				dump_sector(daddr, scsi_debug_sector_size);
1926c6a44287SMartin K. Petersen 				goto out;
1927c6a44287SMartin K. Petersen 			}
1928c6a44287SMartin K. Petersen 
1929395cef03SMartin K. Petersen 			if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1930395cef03SMartin K. Petersen 			    be32_to_cpu(sdt->ref_tag) != ei_lba) {
1931395cef03SMartin K. Petersen 				printk(KERN_ERR
1932395cef03SMartin K. Petersen 				       "%s: REF check failed on sector %lu\n",
1933395cef03SMartin K. Petersen 				       __func__, (unsigned long)sector);
1934395cef03SMartin K. Petersen 				ret = 0x03;
1935395cef03SMartin K. Petersen 				dump_sector(daddr, scsi_debug_sector_size);
1936395cef03SMartin K. Petersen 				goto out;
1937395cef03SMartin K. Petersen 			}
1938395cef03SMartin K. Petersen 
1939c6a44287SMartin K. Petersen 			/* Would be great to copy this in bigger
1940c6a44287SMartin K. Petersen 			 * chunks.  However, for the sake of
1941c6a44287SMartin K. Petersen 			 * correctness we need to verify each sector
1942c6a44287SMartin K. Petersen 			 * before writing it to "stable" storage
1943c6a44287SMartin K. Petersen 			 */
1944c6a44287SMartin K. Petersen 			memcpy(dif_storep + dif_offset(sector), sdt, 8);
1945c6a44287SMartin K. Petersen 
1946c6a44287SMartin K. Petersen 			sector++;
1947c6a44287SMartin K. Petersen 
1948c6a44287SMartin K. Petersen 			if (sector == sdebug_store_sectors)
1949c6a44287SMartin K. Petersen 				sector = 0;	/* Force wrap */
1950c6a44287SMartin K. Petersen 
1951c6a44287SMartin K. Petersen 			start_sec++;
1952395cef03SMartin K. Petersen 			ei_lba++;
1953c6a44287SMartin K. Petersen 			daddr += scsi_debug_sector_size;
1954c6a44287SMartin K. Petersen 			ppage_offset += sizeof(struct sd_dif_tuple);
1955c6a44287SMartin K. Petersen 		}
1956c6a44287SMartin K. Petersen 
1957c6a44287SMartin K. Petersen 		kunmap_atomic(daddr, KM_IRQ0);
1958c6a44287SMartin K. Petersen 	}
1959c6a44287SMartin K. Petersen 
1960c6a44287SMartin K. Petersen 	kunmap_atomic(paddr, KM_IRQ1);
1961c6a44287SMartin K. Petersen 
1962c6a44287SMartin K. Petersen 	dix_writes++;
1963c6a44287SMartin K. Petersen 
1964c6a44287SMartin K. Petersen 	return 0;
1965c6a44287SMartin K. Petersen 
1966c6a44287SMartin K. Petersen out:
1967c6a44287SMartin K. Petersen 	dif_errors++;
1968c6a44287SMartin K. Petersen 	kunmap_atomic(daddr, KM_IRQ0);
1969c6a44287SMartin K. Petersen 	kunmap_atomic(paddr, KM_IRQ1);
1970c6a44287SMartin K. Petersen 	return ret;
1971c6a44287SMartin K. Petersen }
1972c6a44287SMartin K. Petersen 
197344d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
197444d92694SMartin K. Petersen {
197544d92694SMartin K. Petersen 	unsigned int granularity, alignment, mapped;
197644d92694SMartin K. Petersen 	sector_t block, next, end;
197744d92694SMartin K. Petersen 
197844d92694SMartin K. Petersen 	granularity = scsi_debug_unmap_granularity;
197944d92694SMartin K. Petersen 	alignment = granularity - scsi_debug_unmap_alignment;
198044d92694SMartin K. Petersen 	block = lba + alignment;
198144d92694SMartin K. Petersen 	do_div(block, granularity);
198244d92694SMartin K. Petersen 
198344d92694SMartin K. Petersen 	mapped = test_bit(block, map_storep);
198444d92694SMartin K. Petersen 
198544d92694SMartin K. Petersen 	if (mapped)
198644d92694SMartin K. Petersen 		next = find_next_zero_bit(map_storep, map_size, block);
198744d92694SMartin K. Petersen 	else
198844d92694SMartin K. Petersen 		next = find_next_bit(map_storep, map_size, block);
198944d92694SMartin K. Petersen 
199044d92694SMartin K. Petersen 	end = next * granularity - scsi_debug_unmap_alignment;
199144d92694SMartin K. Petersen 	*num = end - lba;
199244d92694SMartin K. Petersen 
199344d92694SMartin K. Petersen 	return mapped;
199444d92694SMartin K. Petersen }
199544d92694SMartin K. Petersen 
199644d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
199744d92694SMartin K. Petersen {
199844d92694SMartin K. Petersen 	unsigned int granularity, alignment;
199944d92694SMartin K. Petersen 	sector_t end = lba + len;
200044d92694SMartin K. Petersen 
200144d92694SMartin K. Petersen 	granularity = scsi_debug_unmap_granularity;
200244d92694SMartin K. Petersen 	alignment = granularity - scsi_debug_unmap_alignment;
200344d92694SMartin K. Petersen 
200444d92694SMartin K. Petersen 	while (lba < end) {
200544d92694SMartin K. Petersen 		sector_t block, rem;
200644d92694SMartin K. Petersen 
200744d92694SMartin K. Petersen 		block = lba + alignment;
200844d92694SMartin K. Petersen 		rem = do_div(block, granularity);
200944d92694SMartin K. Petersen 
20109ab98f57SFUJITA Tomonori 		if (block < map_size)
201144d92694SMartin K. Petersen 			set_bit(block, map_storep);
201244d92694SMartin K. Petersen 
201344d92694SMartin K. Petersen 		lba += granularity - rem;
201444d92694SMartin K. Petersen 	}
201544d92694SMartin K. Petersen }
201644d92694SMartin K. Petersen 
201744d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
201844d92694SMartin K. Petersen {
201944d92694SMartin K. Petersen 	unsigned int granularity, alignment;
202044d92694SMartin K. Petersen 	sector_t end = lba + len;
202144d92694SMartin K. Petersen 
202244d92694SMartin K. Petersen 	granularity = scsi_debug_unmap_granularity;
202344d92694SMartin K. Petersen 	alignment = granularity - scsi_debug_unmap_alignment;
202444d92694SMartin K. Petersen 
202544d92694SMartin K. Petersen 	while (lba < end) {
202644d92694SMartin K. Petersen 		sector_t block, rem;
202744d92694SMartin K. Petersen 
202844d92694SMartin K. Petersen 		block = lba + alignment;
202944d92694SMartin K. Petersen 		rem = do_div(block, granularity);
203044d92694SMartin K. Petersen 
20319ab98f57SFUJITA Tomonori 		if (rem == 0 && lba + granularity <= end &&
20329ab98f57SFUJITA Tomonori 		    block < map_size)
203344d92694SMartin K. Petersen 			clear_bit(block, map_storep);
203444d92694SMartin K. Petersen 
203544d92694SMartin K. Petersen 		lba += granularity - rem;
203644d92694SMartin K. Petersen 	}
203744d92694SMartin K. Petersen }
203844d92694SMartin K. Petersen 
2039c65b1445SDouglas Gilbert static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
2040395cef03SMartin K. Petersen 		      unsigned int num, struct sdebug_dev_info *devip,
2041395cef03SMartin K. Petersen 		      u32 ei_lba)
20421da177e4SLinus Torvalds {
20431da177e4SLinus Torvalds 	unsigned long iflags;
204419789100SFUJITA Tomonori 	int ret;
20451da177e4SLinus Torvalds 
204619789100SFUJITA Tomonori 	ret = check_device_access_params(devip, lba, num);
204719789100SFUJITA Tomonori 	if (ret)
204819789100SFUJITA Tomonori 		return ret;
20491da177e4SLinus Torvalds 
2050c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2051c6a44287SMartin K. Petersen 	if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
2052395cef03SMartin K. Petersen 		int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
2053c6a44287SMartin K. Petersen 
2054c6a44287SMartin K. Petersen 		if (prot_ret) {
2055c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
2056c6a44287SMartin K. Petersen 			return illegal_condition_result;
2057c6a44287SMartin K. Petersen 		}
2058c6a44287SMartin K. Petersen 	}
2059c6a44287SMartin K. Petersen 
20601da177e4SLinus Torvalds 	write_lock_irqsave(&atomic_rw, iflags);
206119789100SFUJITA Tomonori 	ret = do_device_access(SCpnt, devip, lba, num, 1);
206244d92694SMartin K. Petersen 	if (scsi_debug_unmap_granularity)
206344d92694SMartin K. Petersen 		map_region(lba, num);
20641da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
206519789100SFUJITA Tomonori 	if (-1 == ret)
20661da177e4SLinus Torvalds 		return (DID_ERROR << 16);
2067597136abSMartin K. Petersen 	else if ((ret < (num * scsi_debug_sector_size)) &&
20681da177e4SLinus Torvalds 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
2069c65b1445SDouglas Gilbert 		printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
2070597136abSMartin K. Petersen 		       " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
207144d92694SMartin K. Petersen 
20721da177e4SLinus Torvalds 	return 0;
20731da177e4SLinus Torvalds }
20741da177e4SLinus Torvalds 
207544d92694SMartin K. Petersen static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,
207644d92694SMartin K. Petersen 		      unsigned int num, struct sdebug_dev_info *devip,
207744d92694SMartin K. Petersen 			   u32 ei_lba, unsigned int unmap)
207844d92694SMartin K. Petersen {
207944d92694SMartin K. Petersen 	unsigned long iflags;
208044d92694SMartin K. Petersen 	unsigned long long i;
208144d92694SMartin K. Petersen 	int ret;
208244d92694SMartin K. Petersen 
208344d92694SMartin K. Petersen 	ret = check_device_access_params(devip, lba, num);
208444d92694SMartin K. Petersen 	if (ret)
208544d92694SMartin K. Petersen 		return ret;
208644d92694SMartin K. Petersen 
208744d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
208844d92694SMartin K. Petersen 
208944d92694SMartin K. Petersen 	if (unmap && scsi_debug_unmap_granularity) {
209044d92694SMartin K. Petersen 		unmap_region(lba, num);
209144d92694SMartin K. Petersen 		goto out;
209244d92694SMartin K. Petersen 	}
209344d92694SMartin K. Petersen 
209444d92694SMartin K. Petersen 	/* Else fetch one logical block */
209544d92694SMartin K. Petersen 	ret = fetch_to_dev_buffer(scmd,
209644d92694SMartin K. Petersen 				  fake_storep + (lba * scsi_debug_sector_size),
209744d92694SMartin K. Petersen 				  scsi_debug_sector_size);
209844d92694SMartin K. Petersen 
209944d92694SMartin K. Petersen 	if (-1 == ret) {
210044d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
210144d92694SMartin K. Petersen 		return (DID_ERROR << 16);
210244d92694SMartin K. Petersen 	} else if ((ret < (num * scsi_debug_sector_size)) &&
210344d92694SMartin K. Petersen 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
210444d92694SMartin K. Petersen 		printk(KERN_INFO "scsi_debug: write same: cdb indicated=%u, "
210544d92694SMartin K. Petersen 		       " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
210644d92694SMartin K. Petersen 
210744d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
210844d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
210944d92694SMartin K. Petersen 		memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size),
211044d92694SMartin K. Petersen 		       fake_storep + (lba * scsi_debug_sector_size),
211144d92694SMartin K. Petersen 		       scsi_debug_sector_size);
211244d92694SMartin K. Petersen 
211344d92694SMartin K. Petersen 	if (scsi_debug_unmap_granularity)
211444d92694SMartin K. Petersen 		map_region(lba, num);
211544d92694SMartin K. Petersen out:
211644d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
211744d92694SMartin K. Petersen 
211844d92694SMartin K. Petersen 	return 0;
211944d92694SMartin K. Petersen }
212044d92694SMartin K. Petersen 
212144d92694SMartin K. Petersen struct unmap_block_desc {
212244d92694SMartin K. Petersen 	__be64	lba;
212344d92694SMartin K. Petersen 	__be32	blocks;
212444d92694SMartin K. Petersen 	__be32	__reserved;
212544d92694SMartin K. Petersen };
212644d92694SMartin K. Petersen 
212744d92694SMartin K. Petersen static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
212844d92694SMartin K. Petersen {
212944d92694SMartin K. Petersen 	unsigned char *buf;
213044d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
213144d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
213244d92694SMartin K. Petersen 	int ret;
213344d92694SMartin K. Petersen 
213444d92694SMartin K. Petersen 	ret = check_readiness(scmd, 1, devip);
213544d92694SMartin K. Petersen 	if (ret)
213644d92694SMartin K. Petersen 		return ret;
213744d92694SMartin K. Petersen 
213844d92694SMartin K. Petersen 	payload_len = get_unaligned_be16(&scmd->cmnd[7]);
213944d92694SMartin K. Petersen 	BUG_ON(scsi_bufflen(scmd) != payload_len);
214044d92694SMartin K. Petersen 
214144d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
214244d92694SMartin K. Petersen 
214344d92694SMartin K. Petersen 	buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC);
214444d92694SMartin K. Petersen 	if (!buf)
214544d92694SMartin K. Petersen 		return check_condition_result;
214644d92694SMartin K. Petersen 
214744d92694SMartin K. Petersen 	scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
214844d92694SMartin K. Petersen 
214944d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
215044d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
215144d92694SMartin K. Petersen 
215244d92694SMartin K. Petersen 	desc = (void *)&buf[8];
215344d92694SMartin K. Petersen 
215444d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
215544d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
215644d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
215744d92694SMartin K. Petersen 
215844d92694SMartin K. Petersen 		ret = check_device_access_params(devip, lba, num);
215944d92694SMartin K. Petersen 		if (ret)
216044d92694SMartin K. Petersen 			goto out;
216144d92694SMartin K. Petersen 
216244d92694SMartin K. Petersen 		unmap_region(lba, num);
216344d92694SMartin K. Petersen 	}
216444d92694SMartin K. Petersen 
216544d92694SMartin K. Petersen 	ret = 0;
216644d92694SMartin K. Petersen 
216744d92694SMartin K. Petersen out:
216844d92694SMartin K. Petersen 	kfree(buf);
216944d92694SMartin K. Petersen 
217044d92694SMartin K. Petersen 	return ret;
217144d92694SMartin K. Petersen }
217244d92694SMartin K. Petersen 
217344d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
217444d92694SMartin K. Petersen 
217544d92694SMartin K. Petersen static int resp_get_lba_status(struct scsi_cmnd * scmd,
217644d92694SMartin K. Petersen 			       struct sdebug_dev_info * devip)
217744d92694SMartin K. Petersen {
217844d92694SMartin K. Petersen 	unsigned long long lba;
217944d92694SMartin K. Petersen 	unsigned int alloc_len, mapped, num;
218044d92694SMartin K. Petersen 	unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN];
218144d92694SMartin K. Petersen 	int ret;
218244d92694SMartin K. Petersen 
218344d92694SMartin K. Petersen 	ret = check_readiness(scmd, 1, devip);
218444d92694SMartin K. Petersen 	if (ret)
218544d92694SMartin K. Petersen 		return ret;
218644d92694SMartin K. Petersen 
218744d92694SMartin K. Petersen 	lba = get_unaligned_be64(&scmd->cmnd[2]);
218844d92694SMartin K. Petersen 	alloc_len = get_unaligned_be32(&scmd->cmnd[10]);
218944d92694SMartin K. Petersen 
219044d92694SMartin K. Petersen 	if (alloc_len < 24)
219144d92694SMartin K. Petersen 		return 0;
219244d92694SMartin K. Petersen 
219344d92694SMartin K. Petersen 	ret = check_device_access_params(devip, lba, 1);
219444d92694SMartin K. Petersen 	if (ret)
219544d92694SMartin K. Petersen 		return ret;
219644d92694SMartin K. Petersen 
219744d92694SMartin K. Petersen 	mapped = map_state(lba, &num);
219844d92694SMartin K. Petersen 
219944d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
220044d92694SMartin K. Petersen 	put_unaligned_be32(16, &arr[0]);	/* Parameter Data Length */
220144d92694SMartin K. Petersen 	put_unaligned_be64(lba, &arr[8]);	/* LBA */
220244d92694SMartin K. Petersen 	put_unaligned_be32(num, &arr[16]);	/* Number of blocks */
220344d92694SMartin K. Petersen 	arr[20] = !mapped;			/* mapped = 0, unmapped = 1 */
220444d92694SMartin K. Petersen 
220544d92694SMartin K. Petersen 	return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN);
220644d92694SMartin K. Petersen }
220744d92694SMartin K. Petersen 
2208c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256
22091da177e4SLinus Torvalds 
22101da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp,
22111da177e4SLinus Torvalds 			    struct sdebug_dev_info * devip)
22121da177e4SLinus Torvalds {
22131da177e4SLinus Torvalds 	unsigned int alloc_len;
2214c65b1445SDouglas Gilbert 	int lun_cnt, i, upper, num, n, wlun, lun;
22151da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
22161da177e4SLinus Torvalds 	int select_report = (int)cmd[2];
22171da177e4SLinus Torvalds 	struct scsi_lun *one_lun;
22181da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_RLUN_ARR_SZ];
2219c65b1445SDouglas Gilbert 	unsigned char * max_addr;
22201da177e4SLinus Torvalds 
22211da177e4SLinus Torvalds 	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
2222c65b1445SDouglas Gilbert 	if ((alloc_len < 4) || (select_report > 2)) {
22231da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
22241da177e4SLinus Torvalds 			       	0);
22251da177e4SLinus Torvalds 		return check_condition_result;
22261da177e4SLinus Torvalds 	}
22271da177e4SLinus Torvalds 	/* can produce response with up to 16k luns (lun 0 to lun 16383) */
22281da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
22291da177e4SLinus Torvalds 	lun_cnt = scsi_debug_max_luns;
2230c65b1445SDouglas Gilbert 	if (1 == select_report)
2231c65b1445SDouglas Gilbert 		lun_cnt = 0;
2232c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
2233c65b1445SDouglas Gilbert 		--lun_cnt;
2234c65b1445SDouglas Gilbert 	wlun = (select_report > 0) ? 1 : 0;
2235c65b1445SDouglas Gilbert 	num = lun_cnt + wlun;
2236c65b1445SDouglas Gilbert 	arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
2237c65b1445SDouglas Gilbert 	arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
2238c65b1445SDouglas Gilbert 	n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
2239c65b1445SDouglas Gilbert 			    sizeof(struct scsi_lun)), num);
2240c65b1445SDouglas Gilbert 	if (n < num) {
2241c65b1445SDouglas Gilbert 		wlun = 0;
2242c65b1445SDouglas Gilbert 		lun_cnt = n;
2243c65b1445SDouglas Gilbert 	}
22441da177e4SLinus Torvalds 	one_lun = (struct scsi_lun *) &arr[8];
2245c65b1445SDouglas Gilbert 	max_addr = arr + SDEBUG_RLUN_ARR_SZ;
2246c65b1445SDouglas Gilbert 	for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
2247c65b1445SDouglas Gilbert              ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
2248c65b1445SDouglas Gilbert 	     i++, lun++) {
2249c65b1445SDouglas Gilbert 		upper = (lun >> 8) & 0x3f;
22501da177e4SLinus Torvalds 		if (upper)
22511da177e4SLinus Torvalds 			one_lun[i].scsi_lun[0] =
22521da177e4SLinus Torvalds 			    (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
2253c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = lun & 0xff;
22541da177e4SLinus Torvalds 	}
2255c65b1445SDouglas Gilbert 	if (wlun) {
2256c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
2257c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
2258c65b1445SDouglas Gilbert 		i++;
2259c65b1445SDouglas Gilbert 	}
2260c65b1445SDouglas Gilbert 	alloc_len = (unsigned char *)(one_lun + i) - arr;
22611da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr,
22621da177e4SLinus Torvalds 				    min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
22631da177e4SLinus Torvalds }
22641da177e4SLinus Torvalds 
2265c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
2266c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
2267c639d14eSFUJITA Tomonori {
2268c639d14eSFUJITA Tomonori 	int i, j, ret = -1;
2269c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
2270c639d14eSFUJITA Tomonori 	unsigned int offset;
2271c639d14eSFUJITA Tomonori 	struct scatterlist *sg;
2272c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
2273c639d14eSFUJITA Tomonori 
2274c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
2275c639d14eSFUJITA Tomonori 	buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
2276c639d14eSFUJITA Tomonori 	if (!buf)
2277c639d14eSFUJITA Tomonori 		return ret;
2278c639d14eSFUJITA Tomonori 
227921a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
2280c639d14eSFUJITA Tomonori 
2281c639d14eSFUJITA Tomonori 	offset = 0;
2282c639d14eSFUJITA Tomonori 	for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
2283c639d14eSFUJITA Tomonori 		kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
2284c639d14eSFUJITA Tomonori 		if (!kaddr)
2285c639d14eSFUJITA Tomonori 			goto out;
2286c639d14eSFUJITA Tomonori 
2287c639d14eSFUJITA Tomonori 		for (j = 0; j < sg->length; j++)
2288c639d14eSFUJITA Tomonori 			*(kaddr + sg->offset + j) ^= *(buf + offset + j);
2289c639d14eSFUJITA Tomonori 
2290c639d14eSFUJITA Tomonori 		offset += sg->length;
2291c639d14eSFUJITA Tomonori 		kunmap_atomic(kaddr, KM_USER0);
2292c639d14eSFUJITA Tomonori 	}
2293c639d14eSFUJITA Tomonori 	ret = 0;
2294c639d14eSFUJITA Tomonori out:
2295c639d14eSFUJITA Tomonori 	kfree(buf);
2296c639d14eSFUJITA Tomonori 
2297c639d14eSFUJITA Tomonori 	return ret;
2298c639d14eSFUJITA Tomonori }
2299c639d14eSFUJITA Tomonori 
23001da177e4SLinus Torvalds /* When timer goes off this function is called. */
23011da177e4SLinus Torvalds static void timer_intr_handler(unsigned long indx)
23021da177e4SLinus Torvalds {
23031da177e4SLinus Torvalds 	struct sdebug_queued_cmd * sqcp;
23041da177e4SLinus Torvalds 	unsigned long iflags;
23051da177e4SLinus Torvalds 
230678d4e5a0SDouglas Gilbert 	if (indx >= scsi_debug_max_queue) {
23071da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
23081da177e4SLinus Torvalds 		       "large\n");
23091da177e4SLinus Torvalds 		return;
23101da177e4SLinus Torvalds 	}
23111da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
23121da177e4SLinus Torvalds 	sqcp = &queued_arr[(int)indx];
23131da177e4SLinus Torvalds 	if (! sqcp->in_use) {
23141da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
23151da177e4SLinus Torvalds 		       "interrupt\n");
23161da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
23171da177e4SLinus Torvalds 		return;
23181da177e4SLinus Torvalds 	}
23191da177e4SLinus Torvalds 	sqcp->in_use = 0;
23201da177e4SLinus Torvalds 	if (sqcp->done_funct) {
23211da177e4SLinus Torvalds 		sqcp->a_cmnd->result = sqcp->scsi_result;
23221da177e4SLinus Torvalds 		sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
23231da177e4SLinus Torvalds 	}
23241da177e4SLinus Torvalds 	sqcp->done_funct = NULL;
23251da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
23261da177e4SLinus Torvalds }
23271da177e4SLinus Torvalds 
23281da177e4SLinus Torvalds 
23298dea0d02SFUJITA Tomonori static struct sdebug_dev_info *
23308dea0d02SFUJITA Tomonori sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
23315cb2fc06SFUJITA Tomonori {
23325cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
23335cb2fc06SFUJITA Tomonori 
23345cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
23355cb2fc06SFUJITA Tomonori 	if (devip) {
23365cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
23375cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
23385cb2fc06SFUJITA Tomonori 	}
23395cb2fc06SFUJITA Tomonori 	return devip;
23405cb2fc06SFUJITA Tomonori }
23415cb2fc06SFUJITA Tomonori 
23421da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
23431da177e4SLinus Torvalds {
23441da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
23451da177e4SLinus Torvalds 	struct sdebug_dev_info * open_devip = NULL;
23461da177e4SLinus Torvalds 	struct sdebug_dev_info * devip =
23471da177e4SLinus Torvalds 			(struct sdebug_dev_info *)sdev->hostdata;
23481da177e4SLinus Torvalds 
23491da177e4SLinus Torvalds 	if (devip)
23501da177e4SLinus Torvalds 		return devip;
2351d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
23521da177e4SLinus Torvalds 	if (!sdbg_host) {
23531da177e4SLinus Torvalds                 printk(KERN_ERR "Host info NULL\n");
23541da177e4SLinus Torvalds 		return NULL;
23551da177e4SLinus Torvalds         }
23561da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
23571da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
23581da177e4SLinus Torvalds                     (devip->target == sdev->id) &&
23591da177e4SLinus Torvalds                     (devip->lun == sdev->lun))
23601da177e4SLinus Torvalds                         return devip;
23611da177e4SLinus Torvalds 		else {
23621da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
23631da177e4SLinus Torvalds 				open_devip = devip;
23641da177e4SLinus Torvalds 		}
23651da177e4SLinus Torvalds 	}
23665cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
23675cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
23685cb2fc06SFUJITA Tomonori 		if (!open_devip) {
23691da177e4SLinus Torvalds 			printk(KERN_ERR "%s: out of memory at line %d\n",
2370cadbd4a5SHarvey Harrison 				__func__, __LINE__);
23711da177e4SLinus Torvalds 			return NULL;
23721da177e4SLinus Torvalds 		}
23731da177e4SLinus Torvalds 	}
2374a75869d1SFUJITA Tomonori 
23751da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
23761da177e4SLinus Torvalds 	open_devip->target = sdev->id;
23771da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
23781da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
23791da177e4SLinus Torvalds 	open_devip->reset = 1;
23801da177e4SLinus Torvalds 	open_devip->used = 1;
23811da177e4SLinus Torvalds 	memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
23821da177e4SLinus Torvalds 	if (scsi_debug_dsense)
23831da177e4SLinus Torvalds 		open_devip->sense_buff[0] = 0x72;
23841da177e4SLinus Torvalds 	else {
23851da177e4SLinus Torvalds 		open_devip->sense_buff[0] = 0x70;
23861da177e4SLinus Torvalds 		open_devip->sense_buff[7] = 0xa;
23871da177e4SLinus Torvalds 	}
2388c65b1445SDouglas Gilbert 	if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2389c65b1445SDouglas Gilbert 		open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
2390a75869d1SFUJITA Tomonori 
23911da177e4SLinus Torvalds 	return open_devip;
23921da177e4SLinus Torvalds }
23931da177e4SLinus Torvalds 
23948dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
23951da177e4SLinus Torvalds {
23968dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
23978dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
23988dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
239975ad23bcSNick Piggin 	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
24008dea0d02SFUJITA Tomonori 	return 0;
24018dea0d02SFUJITA Tomonori }
24021da177e4SLinus Torvalds 
24038dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
24048dea0d02SFUJITA Tomonori {
24058dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip;
2406a34c4e98SFUJITA Tomonori 
24071da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
24088dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
24098dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
24108dea0d02SFUJITA Tomonori 	if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
24118dea0d02SFUJITA Tomonori 		sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
24128dea0d02SFUJITA Tomonori 	devip = devInfoReg(sdp);
24138dea0d02SFUJITA Tomonori 	if (NULL == devip)
24148dea0d02SFUJITA Tomonori 		return 1;	/* no resources, will be marked offline */
24158dea0d02SFUJITA Tomonori 	sdp->hostdata = devip;
24168dea0d02SFUJITA Tomonori 	if (sdp->host->cmd_per_lun)
24178dea0d02SFUJITA Tomonori 		scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
24188dea0d02SFUJITA Tomonori 					sdp->host->cmd_per_lun);
24198dea0d02SFUJITA Tomonori 	blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
242078d4e5a0SDouglas Gilbert 	if (scsi_debug_no_uld)
242178d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
24228dea0d02SFUJITA Tomonori 	return 0;
24238dea0d02SFUJITA Tomonori }
24248dea0d02SFUJITA Tomonori 
24258dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
24268dea0d02SFUJITA Tomonori {
24278dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
24288dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
24298dea0d02SFUJITA Tomonori 
24308dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
24318dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
24328dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
24338dea0d02SFUJITA Tomonori 	if (devip) {
24348dea0d02SFUJITA Tomonori 		/* make this slot avaliable for re-use */
24358dea0d02SFUJITA Tomonori 		devip->used = 0;
24368dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
24378dea0d02SFUJITA Tomonori 	}
24388dea0d02SFUJITA Tomonori }
24398dea0d02SFUJITA Tomonori 
24408dea0d02SFUJITA Tomonori /* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
24418dea0d02SFUJITA Tomonori static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
24428dea0d02SFUJITA Tomonori {
24438dea0d02SFUJITA Tomonori 	unsigned long iflags;
24448dea0d02SFUJITA Tomonori 	int k;
24458dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
24468dea0d02SFUJITA Tomonori 
24478dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
244878d4e5a0SDouglas Gilbert 	for (k = 0; k < scsi_debug_max_queue; ++k) {
24498dea0d02SFUJITA Tomonori 		sqcp = &queued_arr[k];
24508dea0d02SFUJITA Tomonori 		if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
24518dea0d02SFUJITA Tomonori 			del_timer_sync(&sqcp->cmnd_timer);
24528dea0d02SFUJITA Tomonori 			sqcp->in_use = 0;
24538dea0d02SFUJITA Tomonori 			sqcp->a_cmnd = NULL;
24548dea0d02SFUJITA Tomonori 			break;
24558dea0d02SFUJITA Tomonori 		}
24568dea0d02SFUJITA Tomonori 	}
24578dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
245878d4e5a0SDouglas Gilbert 	return (k < scsi_debug_max_queue) ? 1 : 0;
24598dea0d02SFUJITA Tomonori }
24608dea0d02SFUJITA Tomonori 
24618dea0d02SFUJITA Tomonori /* Deletes (stops) timers of all queued commands */
24628dea0d02SFUJITA Tomonori static void stop_all_queued(void)
24638dea0d02SFUJITA Tomonori {
24648dea0d02SFUJITA Tomonori 	unsigned long iflags;
24658dea0d02SFUJITA Tomonori 	int k;
24668dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
24678dea0d02SFUJITA Tomonori 
24688dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
246978d4e5a0SDouglas Gilbert 	for (k = 0; k < scsi_debug_max_queue; ++k) {
24708dea0d02SFUJITA Tomonori 		sqcp = &queued_arr[k];
24718dea0d02SFUJITA Tomonori 		if (sqcp->in_use && sqcp->a_cmnd) {
24728dea0d02SFUJITA Tomonori 			del_timer_sync(&sqcp->cmnd_timer);
24738dea0d02SFUJITA Tomonori 			sqcp->in_use = 0;
24748dea0d02SFUJITA Tomonori 			sqcp->a_cmnd = NULL;
24758dea0d02SFUJITA Tomonori 		}
24768dea0d02SFUJITA Tomonori 	}
24778dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
24781da177e4SLinus Torvalds }
24791da177e4SLinus Torvalds 
24801da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
24811da177e4SLinus Torvalds {
24821da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
24831da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: abort\n");
24841da177e4SLinus Torvalds 	++num_aborts;
24851da177e4SLinus Torvalds 	stop_queued_cmnd(SCpnt);
24861da177e4SLinus Torvalds 	return SUCCESS;
24871da177e4SLinus Torvalds }
24881da177e4SLinus Torvalds 
24891da177e4SLinus Torvalds static int scsi_debug_biosparam(struct scsi_device *sdev,
24901da177e4SLinus Torvalds 		struct block_device * bdev, sector_t capacity, int *info)
24911da177e4SLinus Torvalds {
24921da177e4SLinus Torvalds 	int res;
24931da177e4SLinus Torvalds 	unsigned char *buf;
24941da177e4SLinus Torvalds 
24951da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
24961da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: biosparam\n");
24971da177e4SLinus Torvalds 	buf = scsi_bios_ptable(bdev);
24981da177e4SLinus Torvalds 	if (buf) {
24991da177e4SLinus Torvalds 		res = scsi_partsize(buf, capacity,
25001da177e4SLinus Torvalds 				    &info[2], &info[0], &info[1]);
25011da177e4SLinus Torvalds 		kfree(buf);
25021da177e4SLinus Torvalds 		if (! res)
25031da177e4SLinus Torvalds 			return res;
25041da177e4SLinus Torvalds 	}
25051da177e4SLinus Torvalds 	info[0] = sdebug_heads;
25061da177e4SLinus Torvalds 	info[1] = sdebug_sectors_per;
25071da177e4SLinus Torvalds 	info[2] = sdebug_cylinders_per;
25081da177e4SLinus Torvalds 	return 0;
25091da177e4SLinus Torvalds }
25101da177e4SLinus Torvalds 
25111da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
25121da177e4SLinus Torvalds {
25131da177e4SLinus Torvalds 	struct sdebug_dev_info * devip;
25141da177e4SLinus Torvalds 
25151da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25161da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: device_reset\n");
25171da177e4SLinus Torvalds 	++num_dev_resets;
25181da177e4SLinus Torvalds 	if (SCpnt) {
25191da177e4SLinus Torvalds 		devip = devInfoReg(SCpnt->device);
25201da177e4SLinus Torvalds 		if (devip)
25211da177e4SLinus Torvalds 			devip->reset = 1;
25221da177e4SLinus Torvalds 	}
25231da177e4SLinus Torvalds 	return SUCCESS;
25241da177e4SLinus Torvalds }
25251da177e4SLinus Torvalds 
25261da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
25271da177e4SLinus Torvalds {
25281da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
25291da177e4SLinus Torvalds         struct sdebug_dev_info * dev_info;
25301da177e4SLinus Torvalds         struct scsi_device * sdp;
25311da177e4SLinus Torvalds         struct Scsi_Host * hp;
25321da177e4SLinus Torvalds 
25331da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25341da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: bus_reset\n");
25351da177e4SLinus Torvalds 	++num_bus_resets;
25361da177e4SLinus Torvalds 	if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
2537d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
25381da177e4SLinus Torvalds 		if (sdbg_host) {
25391da177e4SLinus Torvalds 			list_for_each_entry(dev_info,
25401da177e4SLinus Torvalds                                             &sdbg_host->dev_info_list,
25411da177e4SLinus Torvalds                                             dev_list)
25421da177e4SLinus Torvalds 				dev_info->reset = 1;
25431da177e4SLinus Torvalds 		}
25441da177e4SLinus Torvalds 	}
25451da177e4SLinus Torvalds 	return SUCCESS;
25461da177e4SLinus Torvalds }
25471da177e4SLinus Torvalds 
25481da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
25491da177e4SLinus Torvalds {
25501da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
25511da177e4SLinus Torvalds         struct sdebug_dev_info * dev_info;
25521da177e4SLinus Torvalds 
25531da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25541da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: host_reset\n");
25551da177e4SLinus Torvalds 	++num_host_resets;
25561da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
25571da177e4SLinus Torvalds         list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
25581da177e4SLinus Torvalds                 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
25591da177e4SLinus Torvalds                                     dev_list)
25601da177e4SLinus Torvalds                         dev_info->reset = 1;
25611da177e4SLinus Torvalds         }
25621da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
25631da177e4SLinus Torvalds 	stop_all_queued();
25641da177e4SLinus Torvalds 	return SUCCESS;
25651da177e4SLinus Torvalds }
25661da177e4SLinus Torvalds 
25671da177e4SLinus Torvalds /* Initializes timers in queued array */
25681da177e4SLinus Torvalds static void __init init_all_queued(void)
25691da177e4SLinus Torvalds {
25701da177e4SLinus Torvalds 	unsigned long iflags;
25711da177e4SLinus Torvalds 	int k;
25721da177e4SLinus Torvalds 	struct sdebug_queued_cmd * sqcp;
25731da177e4SLinus Torvalds 
25741da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
257578d4e5a0SDouglas Gilbert 	for (k = 0; k < scsi_debug_max_queue; ++k) {
25761da177e4SLinus Torvalds 		sqcp = &queued_arr[k];
25771da177e4SLinus Torvalds 		init_timer(&sqcp->cmnd_timer);
25781da177e4SLinus Torvalds 		sqcp->in_use = 0;
25791da177e4SLinus Torvalds 		sqcp->a_cmnd = NULL;
25801da177e4SLinus Torvalds 	}
25811da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
25821da177e4SLinus Torvalds }
25831da177e4SLinus Torvalds 
2584f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
25855f2578e5SFUJITA Tomonori 				      unsigned long store_size)
25861da177e4SLinus Torvalds {
25871da177e4SLinus Torvalds 	struct partition * pp;
25881da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
25891da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
25901da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
25911da177e4SLinus Torvalds 
25921da177e4SLinus Torvalds 	/* assume partition table already zeroed */
2593f58b0efbSFUJITA Tomonori 	if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
25941da177e4SLinus Torvalds 		return;
25951da177e4SLinus Torvalds 	if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
25961da177e4SLinus Torvalds 		scsi_debug_num_parts = SDEBUG_MAX_PARTS;
25971da177e4SLinus Torvalds 		printk(KERN_WARNING "scsi_debug:build_parts: reducing "
25981da177e4SLinus Torvalds 				    "partitions to %d\n", SDEBUG_MAX_PARTS);
25991da177e4SLinus Torvalds 	}
2600c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
26011da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
26021da177e4SLinus Torvalds 			   / scsi_debug_num_parts;
26031da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
26041da177e4SLinus Torvalds         starts[0] = sdebug_sectors_per;
26051da177e4SLinus Torvalds 	for (k = 1; k < scsi_debug_num_parts; ++k)
26061da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
26071da177e4SLinus Torvalds 			    * heads_by_sects;
26081da177e4SLinus Torvalds 	starts[scsi_debug_num_parts] = num_sectors;
26091da177e4SLinus Torvalds 	starts[scsi_debug_num_parts + 1] = 0;
26101da177e4SLinus Torvalds 
26111da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
26121da177e4SLinus Torvalds 	ramp[511] = 0xAA;
26131da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
26141da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
26151da177e4SLinus Torvalds 		start_sec = starts[k];
26161da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
26171da177e4SLinus Torvalds 		pp->boot_ind = 0;
26181da177e4SLinus Torvalds 
26191da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
26201da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
26211da177e4SLinus Torvalds 			   / sdebug_sectors_per;
26221da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
26231da177e4SLinus Torvalds 
26241da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
26251da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
26261da177e4SLinus Torvalds 			       / sdebug_sectors_per;
26271da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
26281da177e4SLinus Torvalds 
26291da177e4SLinus Torvalds 		pp->start_sect = start_sec;
26301da177e4SLinus Torvalds 		pp->nr_sects = end_sec - start_sec + 1;
26311da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
26321da177e4SLinus Torvalds 	}
26331da177e4SLinus Torvalds }
26341da177e4SLinus Torvalds 
26351da177e4SLinus Torvalds static int schedule_resp(struct scsi_cmnd * cmnd,
26361da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip,
26371da177e4SLinus Torvalds 			 done_funct_t done, int scsi_result, int delta_jiff)
26381da177e4SLinus Torvalds {
26391da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
26401da177e4SLinus Torvalds 		if (scsi_result) {
26411da177e4SLinus Torvalds 			struct scsi_device * sdp = cmnd->device;
26421da177e4SLinus Torvalds 
2643c65b1445SDouglas Gilbert 			printk(KERN_INFO "scsi_debug:    <%u %u %u %u> "
2644c65b1445SDouglas Gilbert 			       "non-zero result=0x%x\n", sdp->host->host_no,
2645c65b1445SDouglas Gilbert 			       sdp->channel, sdp->id, sdp->lun, scsi_result);
26461da177e4SLinus Torvalds 		}
26471da177e4SLinus Torvalds 	}
26481da177e4SLinus Torvalds 	if (cmnd && devip) {
26491da177e4SLinus Torvalds 		/* simulate autosense by this driver */
26501da177e4SLinus Torvalds 		if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
26511da177e4SLinus Torvalds 			memcpy(cmnd->sense_buffer, devip->sense_buff,
26521da177e4SLinus Torvalds 			       (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
26531da177e4SLinus Torvalds 			       SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
26541da177e4SLinus Torvalds 	}
26551da177e4SLinus Torvalds 	if (delta_jiff <= 0) {
26561da177e4SLinus Torvalds 		if (cmnd)
26571da177e4SLinus Torvalds 			cmnd->result = scsi_result;
26581da177e4SLinus Torvalds 		if (done)
26591da177e4SLinus Torvalds 			done(cmnd);
26601da177e4SLinus Torvalds 		return 0;
26611da177e4SLinus Torvalds 	} else {
26621da177e4SLinus Torvalds 		unsigned long iflags;
26631da177e4SLinus Torvalds 		int k;
26641da177e4SLinus Torvalds 		struct sdebug_queued_cmd * sqcp = NULL;
26651da177e4SLinus Torvalds 
26661da177e4SLinus Torvalds 		spin_lock_irqsave(&queued_arr_lock, iflags);
266778d4e5a0SDouglas Gilbert 		for (k = 0; k < scsi_debug_max_queue; ++k) {
26681da177e4SLinus Torvalds 			sqcp = &queued_arr[k];
26691da177e4SLinus Torvalds 			if (! sqcp->in_use)
26701da177e4SLinus Torvalds 				break;
26711da177e4SLinus Torvalds 		}
267278d4e5a0SDouglas Gilbert 		if (k >= scsi_debug_max_queue) {
26731da177e4SLinus Torvalds 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
26741da177e4SLinus Torvalds 			printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
26751da177e4SLinus Torvalds 			return 1;	/* report busy to mid level */
26761da177e4SLinus Torvalds 		}
26771da177e4SLinus Torvalds 		sqcp->in_use = 1;
26781da177e4SLinus Torvalds 		sqcp->a_cmnd = cmnd;
26791da177e4SLinus Torvalds 		sqcp->scsi_result = scsi_result;
26801da177e4SLinus Torvalds 		sqcp->done_funct = done;
26811da177e4SLinus Torvalds 		sqcp->cmnd_timer.function = timer_intr_handler;
26821da177e4SLinus Torvalds 		sqcp->cmnd_timer.data = k;
26831da177e4SLinus Torvalds 		sqcp->cmnd_timer.expires = jiffies + delta_jiff;
26841da177e4SLinus Torvalds 		add_timer(&sqcp->cmnd_timer);
26851da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
26861da177e4SLinus Torvalds 		if (cmnd)
26871da177e4SLinus Torvalds 			cmnd->result = 0;
26881da177e4SLinus Torvalds 		return 0;
26891da177e4SLinus Torvalds 	}
26901da177e4SLinus Torvalds }
269123183910SDouglas Gilbert /* Note: The following macros create attribute files in the
269223183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
269323183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
269423183910SDouglas Gilbert    as it can when the corresponding attribute in the
269523183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
269623183910SDouglas Gilbert  */
2697c65b1445SDouglas Gilbert module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2698c65b1445SDouglas Gilbert module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2699c65b1445SDouglas Gilbert module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2700c65b1445SDouglas Gilbert module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2701c65b1445SDouglas Gilbert module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
270223183910SDouglas Gilbert module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
2703c65b1445SDouglas Gilbert module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
270478d4e5a0SDouglas Gilbert module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);
2705c65b1445SDouglas Gilbert module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
270678d4e5a0SDouglas Gilbert module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);
2707c65b1445SDouglas Gilbert module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2708c65b1445SDouglas Gilbert module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2709c65b1445SDouglas Gilbert module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2710c65b1445SDouglas Gilbert module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2711c65b1445SDouglas Gilbert module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2712c65b1445SDouglas Gilbert module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
271323183910SDouglas Gilbert module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
271423183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
2715597136abSMartin K. Petersen module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
2716c6a44287SMartin K. Petersen module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
2717c6a44287SMartin K. Petersen module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
2718c6a44287SMartin K. Petersen module_param_named(guard, scsi_debug_guard, int, S_IRUGO);
2719c6a44287SMartin K. Petersen module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
2720ea61fca5SMartin K. Petersen module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
2721e308b3d1SMartin K. Petersen module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO);
2722ea61fca5SMartin K. Petersen module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
272344d92694SMartin K. Petersen module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
272444d92694SMartin K. Petersen module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
272544d92694SMartin K. Petersen module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
272644d92694SMartin K. Petersen module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
27276014759cSMartin K. Petersen module_param_named(tpu, scsi_debug_tpu, int, S_IRUGO);
27286014759cSMartin K. Petersen module_param_named(tpws, scsi_debug_tpws, int, S_IRUGO);
27291da177e4SLinus Torvalds 
27301da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
27311da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
27321da177e4SLinus Torvalds MODULE_LICENSE("GPL");
27331da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION);
27341da177e4SLinus Torvalds 
27351da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
27361da177e4SLinus Torvalds MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
2737c65b1445SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2738c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
2739beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
274023183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
2741c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
274278d4e5a0SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to 255(def))");
2743c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
274478d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
27451da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
2746c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
27476f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
27481da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
27491da177e4SLinus Torvalds MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
2750c65b1445SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
275123183910SDouglas Gilbert MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
2752ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
2753ea61fca5SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
2754e308b3d1SMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
2755ea61fca5SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
2756c6a44287SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
2757c6a44287SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
2758c6a44287SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
2759c6a44287SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
27606014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
27616014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
27626014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
276344d92694SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
27646014759cSMartin K. Petersen MODULE_PARM_DESC(tpu, "enable TP, support UNMAP command (def=0)");
27656014759cSMartin K. Petersen MODULE_PARM_DESC(tpws, "enable TP, support WRITE SAME(16) with UNMAP bit (def=0)");
27661da177e4SLinus Torvalds 
27671da177e4SLinus Torvalds static char sdebug_info[256];
27681da177e4SLinus Torvalds 
27691da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp)
27701da177e4SLinus Torvalds {
27711da177e4SLinus Torvalds 	sprintf(sdebug_info, "scsi_debug, version %s [%s], "
27721da177e4SLinus Torvalds 		"dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
27731da177e4SLinus Torvalds 		scsi_debug_version_date, scsi_debug_dev_size_mb,
27741da177e4SLinus Torvalds 		scsi_debug_opts);
27751da177e4SLinus Torvalds 	return sdebug_info;
27761da177e4SLinus Torvalds }
27771da177e4SLinus Torvalds 
27781da177e4SLinus Torvalds /* scsi_debug_proc_info
27791da177e4SLinus Torvalds  * Used if the driver currently has no own support for /proc/scsi
27801da177e4SLinus Torvalds  */
27811da177e4SLinus Torvalds static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
27821da177e4SLinus Torvalds 				int length, int inout)
27831da177e4SLinus Torvalds {
27841da177e4SLinus Torvalds 	int len, pos, begin;
27851da177e4SLinus Torvalds 	int orig_length;
27861da177e4SLinus Torvalds 
27871da177e4SLinus Torvalds 	orig_length = length;
27881da177e4SLinus Torvalds 
27891da177e4SLinus Torvalds 	if (inout == 1) {
27901da177e4SLinus Torvalds 		char arr[16];
27911da177e4SLinus Torvalds 		int minLen = length > 15 ? 15 : length;
27921da177e4SLinus Torvalds 
27931da177e4SLinus Torvalds 		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
27941da177e4SLinus Torvalds 			return -EACCES;
27951da177e4SLinus Torvalds 		memcpy(arr, buffer, minLen);
27961da177e4SLinus Torvalds 		arr[minLen] = '\0';
27971da177e4SLinus Torvalds 		if (1 != sscanf(arr, "%d", &pos))
27981da177e4SLinus Torvalds 			return -EINVAL;
27991da177e4SLinus Torvalds 		scsi_debug_opts = pos;
28001da177e4SLinus Torvalds 		if (scsi_debug_every_nth != 0)
28011da177e4SLinus Torvalds                         scsi_debug_cmnd_count = 0;
28021da177e4SLinus Torvalds 		return length;
28031da177e4SLinus Torvalds 	}
28041da177e4SLinus Torvalds 	begin = 0;
28051da177e4SLinus Torvalds 	pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
28061da177e4SLinus Torvalds 	    "%s [%s]\n"
28071da177e4SLinus Torvalds 	    "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
28081da177e4SLinus Torvalds 	    "every_nth=%d(curr:%d)\n"
28091da177e4SLinus Torvalds 	    "delay=%d, max_luns=%d, scsi_level=%d\n"
28101da177e4SLinus Torvalds 	    "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
28111da177e4SLinus Torvalds 	    "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2812c6a44287SMartin K. Petersen 	    "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n",
28131da177e4SLinus Torvalds 	    SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
28141da177e4SLinus Torvalds 	    scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
28151da177e4SLinus Torvalds 	    scsi_debug_cmnd_count, scsi_debug_delay,
28161da177e4SLinus Torvalds 	    scsi_debug_max_luns, scsi_debug_scsi_level,
2817597136abSMartin K. Petersen 	    scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
2818597136abSMartin K. Petersen 	    sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
2819c6a44287SMartin K. Petersen 	    num_host_resets, dix_reads, dix_writes, dif_errors);
28201da177e4SLinus Torvalds 	if (pos < offset) {
28211da177e4SLinus Torvalds 		len = 0;
28221da177e4SLinus Torvalds 		begin = pos;
28231da177e4SLinus Torvalds 	}
28241da177e4SLinus Torvalds 	*start = buffer + (offset - begin);	/* Start of wanted data */
28251da177e4SLinus Torvalds 	len -= (offset - begin);
28261da177e4SLinus Torvalds 	if (len > length)
28271da177e4SLinus Torvalds 		len = length;
28281da177e4SLinus Torvalds 	return len;
28291da177e4SLinus Torvalds }
28301da177e4SLinus Torvalds 
28311da177e4SLinus Torvalds static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
28321da177e4SLinus Torvalds {
28331da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
28341da177e4SLinus Torvalds }
28351da177e4SLinus Torvalds 
28361da177e4SLinus Torvalds static ssize_t sdebug_delay_store(struct device_driver * ddp,
28371da177e4SLinus Torvalds 				  const char * buf, size_t count)
28381da177e4SLinus Torvalds {
28391da177e4SLinus Torvalds         int delay;
28401da177e4SLinus Torvalds 	char work[20];
28411da177e4SLinus Torvalds 
28421da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
28431da177e4SLinus Torvalds 		if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
28441da177e4SLinus Torvalds 			scsi_debug_delay = delay;
28451da177e4SLinus Torvalds 			return count;
28461da177e4SLinus Torvalds 		}
28471da177e4SLinus Torvalds 	}
28481da177e4SLinus Torvalds 	return -EINVAL;
28491da177e4SLinus Torvalds }
28501da177e4SLinus Torvalds DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
28511da177e4SLinus Torvalds 	    sdebug_delay_store);
28521da177e4SLinus Torvalds 
28531da177e4SLinus Torvalds static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
28541da177e4SLinus Torvalds {
28551da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
28561da177e4SLinus Torvalds }
28571da177e4SLinus Torvalds 
28581da177e4SLinus Torvalds static ssize_t sdebug_opts_store(struct device_driver * ddp,
28591da177e4SLinus Torvalds 				 const char * buf, size_t count)
28601da177e4SLinus Torvalds {
28611da177e4SLinus Torvalds         int opts;
28621da177e4SLinus Torvalds 	char work[20];
28631da177e4SLinus Torvalds 
28641da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
28651da177e4SLinus Torvalds 		if (0 == strnicmp(work,"0x", 2)) {
28661da177e4SLinus Torvalds 			if (1 == sscanf(&work[2], "%x", &opts))
28671da177e4SLinus Torvalds 				goto opts_done;
28681da177e4SLinus Torvalds 		} else {
28691da177e4SLinus Torvalds 			if (1 == sscanf(work, "%d", &opts))
28701da177e4SLinus Torvalds 				goto opts_done;
28711da177e4SLinus Torvalds 		}
28721da177e4SLinus Torvalds 	}
28731da177e4SLinus Torvalds 	return -EINVAL;
28741da177e4SLinus Torvalds opts_done:
28751da177e4SLinus Torvalds 	scsi_debug_opts = opts;
28761da177e4SLinus Torvalds 	scsi_debug_cmnd_count = 0;
28771da177e4SLinus Torvalds 	return count;
28781da177e4SLinus Torvalds }
28791da177e4SLinus Torvalds DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
28801da177e4SLinus Torvalds 	    sdebug_opts_store);
28811da177e4SLinus Torvalds 
28821da177e4SLinus Torvalds static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
28831da177e4SLinus Torvalds {
28841da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
28851da177e4SLinus Torvalds }
28861da177e4SLinus Torvalds static ssize_t sdebug_ptype_store(struct device_driver * ddp,
28871da177e4SLinus Torvalds 				  const char * buf, size_t count)
28881da177e4SLinus Torvalds {
28891da177e4SLinus Torvalds         int n;
28901da177e4SLinus Torvalds 
28911da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
28921da177e4SLinus Torvalds 		scsi_debug_ptype = n;
28931da177e4SLinus Torvalds 		return count;
28941da177e4SLinus Torvalds 	}
28951da177e4SLinus Torvalds 	return -EINVAL;
28961da177e4SLinus Torvalds }
28971da177e4SLinus Torvalds DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
28981da177e4SLinus Torvalds 
28991da177e4SLinus Torvalds static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
29001da177e4SLinus Torvalds {
29011da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
29021da177e4SLinus Torvalds }
29031da177e4SLinus Torvalds static ssize_t sdebug_dsense_store(struct device_driver * ddp,
29041da177e4SLinus Torvalds 				  const char * buf, size_t count)
29051da177e4SLinus Torvalds {
29061da177e4SLinus Torvalds         int n;
29071da177e4SLinus Torvalds 
29081da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
29091da177e4SLinus Torvalds 		scsi_debug_dsense = n;
29101da177e4SLinus Torvalds 		return count;
29111da177e4SLinus Torvalds 	}
29121da177e4SLinus Torvalds 	return -EINVAL;
29131da177e4SLinus Torvalds }
29141da177e4SLinus Torvalds DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
29151da177e4SLinus Torvalds 	    sdebug_dsense_store);
29161da177e4SLinus Torvalds 
291723183910SDouglas Gilbert static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
291823183910SDouglas Gilbert {
291923183910SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
292023183910SDouglas Gilbert }
292123183910SDouglas Gilbert static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
292223183910SDouglas Gilbert 				    const char * buf, size_t count)
292323183910SDouglas Gilbert {
292423183910SDouglas Gilbert         int n;
292523183910SDouglas Gilbert 
292623183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
292723183910SDouglas Gilbert 		scsi_debug_fake_rw = n;
292823183910SDouglas Gilbert 		return count;
292923183910SDouglas Gilbert 	}
293023183910SDouglas Gilbert 	return -EINVAL;
293123183910SDouglas Gilbert }
293223183910SDouglas Gilbert DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
293323183910SDouglas Gilbert 	    sdebug_fake_rw_store);
293423183910SDouglas Gilbert 
2935c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2936c65b1445SDouglas Gilbert {
2937c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2938c65b1445SDouglas Gilbert }
2939c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2940c65b1445SDouglas Gilbert 				     const char * buf, size_t count)
2941c65b1445SDouglas Gilbert {
2942c65b1445SDouglas Gilbert         int n;
2943c65b1445SDouglas Gilbert 
2944c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2945c65b1445SDouglas Gilbert 		scsi_debug_no_lun_0 = n;
2946c65b1445SDouglas Gilbert 		return count;
2947c65b1445SDouglas Gilbert 	}
2948c65b1445SDouglas Gilbert 	return -EINVAL;
2949c65b1445SDouglas Gilbert }
2950c65b1445SDouglas Gilbert DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2951c65b1445SDouglas Gilbert 	    sdebug_no_lun_0_store);
2952c65b1445SDouglas Gilbert 
29531da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
29541da177e4SLinus Torvalds {
29551da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
29561da177e4SLinus Torvalds }
29571da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
29581da177e4SLinus Torvalds 				     const char * buf, size_t count)
29591da177e4SLinus Torvalds {
29601da177e4SLinus Torvalds         int n;
29611da177e4SLinus Torvalds 
29621da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
29631da177e4SLinus Torvalds 		scsi_debug_num_tgts = n;
29641da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
29651da177e4SLinus Torvalds 		return count;
29661da177e4SLinus Torvalds 	}
29671da177e4SLinus Torvalds 	return -EINVAL;
29681da177e4SLinus Torvalds }
29691da177e4SLinus Torvalds DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
29701da177e4SLinus Torvalds 	    sdebug_num_tgts_store);
29711da177e4SLinus Torvalds 
29721da177e4SLinus Torvalds static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
29731da177e4SLinus Torvalds {
29741da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
29751da177e4SLinus Torvalds }
29761da177e4SLinus Torvalds DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
29771da177e4SLinus Torvalds 
29781da177e4SLinus Torvalds static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
29791da177e4SLinus Torvalds {
29801da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
29811da177e4SLinus Torvalds }
29821da177e4SLinus Torvalds DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
29831da177e4SLinus Torvalds 
29841da177e4SLinus Torvalds static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
29851da177e4SLinus Torvalds {
29861da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
29871da177e4SLinus Torvalds }
29881da177e4SLinus Torvalds static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
29891da177e4SLinus Torvalds 				      const char * buf, size_t count)
29901da177e4SLinus Torvalds {
29911da177e4SLinus Torvalds         int nth;
29921da177e4SLinus Torvalds 
29931da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
29941da177e4SLinus Torvalds 		scsi_debug_every_nth = nth;
29951da177e4SLinus Torvalds 		scsi_debug_cmnd_count = 0;
29961da177e4SLinus Torvalds 		return count;
29971da177e4SLinus Torvalds 	}
29981da177e4SLinus Torvalds 	return -EINVAL;
29991da177e4SLinus Torvalds }
30001da177e4SLinus Torvalds DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
30011da177e4SLinus Torvalds 	    sdebug_every_nth_store);
30021da177e4SLinus Torvalds 
30031da177e4SLinus Torvalds static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
30041da177e4SLinus Torvalds {
30051da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
30061da177e4SLinus Torvalds }
30071da177e4SLinus Torvalds static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
30081da177e4SLinus Torvalds 				     const char * buf, size_t count)
30091da177e4SLinus Torvalds {
30101da177e4SLinus Torvalds         int n;
30111da177e4SLinus Torvalds 
30121da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
30131da177e4SLinus Torvalds 		scsi_debug_max_luns = n;
30141da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
30151da177e4SLinus Torvalds 		return count;
30161da177e4SLinus Torvalds 	}
30171da177e4SLinus Torvalds 	return -EINVAL;
30181da177e4SLinus Torvalds }
30191da177e4SLinus Torvalds DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
30201da177e4SLinus Torvalds 	    sdebug_max_luns_store);
30211da177e4SLinus Torvalds 
302278d4e5a0SDouglas Gilbert static ssize_t sdebug_max_queue_show(struct device_driver * ddp, char * buf)
302378d4e5a0SDouglas Gilbert {
302478d4e5a0SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue);
302578d4e5a0SDouglas Gilbert }
302678d4e5a0SDouglas Gilbert static ssize_t sdebug_max_queue_store(struct device_driver * ddp,
302778d4e5a0SDouglas Gilbert 				      const char * buf, size_t count)
302878d4e5a0SDouglas Gilbert {
302978d4e5a0SDouglas Gilbert         int n;
303078d4e5a0SDouglas Gilbert 
303178d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
303278d4e5a0SDouglas Gilbert 	    (n <= SCSI_DEBUG_CANQUEUE)) {
303378d4e5a0SDouglas Gilbert 		scsi_debug_max_queue = n;
303478d4e5a0SDouglas Gilbert 		return count;
303578d4e5a0SDouglas Gilbert 	}
303678d4e5a0SDouglas Gilbert 	return -EINVAL;
303778d4e5a0SDouglas Gilbert }
303878d4e5a0SDouglas Gilbert DRIVER_ATTR(max_queue, S_IRUGO | S_IWUSR, sdebug_max_queue_show,
303978d4e5a0SDouglas Gilbert 	    sdebug_max_queue_store);
304078d4e5a0SDouglas Gilbert 
304178d4e5a0SDouglas Gilbert static ssize_t sdebug_no_uld_show(struct device_driver * ddp, char * buf)
304278d4e5a0SDouglas Gilbert {
304378d4e5a0SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld);
304478d4e5a0SDouglas Gilbert }
304578d4e5a0SDouglas Gilbert DRIVER_ATTR(no_uld, S_IRUGO, sdebug_no_uld_show, NULL);
304678d4e5a0SDouglas Gilbert 
30471da177e4SLinus Torvalds static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
30481da177e4SLinus Torvalds {
30491da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
30501da177e4SLinus Torvalds }
30511da177e4SLinus Torvalds DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
30521da177e4SLinus Torvalds 
3053c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
3054c65b1445SDouglas Gilbert {
3055c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
3056c65b1445SDouglas Gilbert }
3057c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
3058c65b1445SDouglas Gilbert 				       const char * buf, size_t count)
3059c65b1445SDouglas Gilbert {
3060c65b1445SDouglas Gilbert         int n;
3061c65b1445SDouglas Gilbert 
3062c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3063c65b1445SDouglas Gilbert 		scsi_debug_virtual_gb = n;
306428898873SFUJITA Tomonori 
306528898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
306628898873SFUJITA Tomonori 
3067c65b1445SDouglas Gilbert 		return count;
3068c65b1445SDouglas Gilbert 	}
3069c65b1445SDouglas Gilbert 	return -EINVAL;
3070c65b1445SDouglas Gilbert }
3071c65b1445SDouglas Gilbert DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
3072c65b1445SDouglas Gilbert 	    sdebug_virtual_gb_store);
3073c65b1445SDouglas Gilbert 
30741da177e4SLinus Torvalds static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
30751da177e4SLinus Torvalds {
30761da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
30771da177e4SLinus Torvalds }
30781da177e4SLinus Torvalds 
30791da177e4SLinus Torvalds static ssize_t sdebug_add_host_store(struct device_driver * ddp,
30801da177e4SLinus Torvalds 				     const char * buf, size_t count)
30811da177e4SLinus Torvalds {
30821da177e4SLinus Torvalds 	int delta_hosts;
30831da177e4SLinus Torvalds 
3084f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
30851da177e4SLinus Torvalds 		return -EINVAL;
30861da177e4SLinus Torvalds 	if (delta_hosts > 0) {
30871da177e4SLinus Torvalds 		do {
30881da177e4SLinus Torvalds 			sdebug_add_adapter();
30891da177e4SLinus Torvalds 		} while (--delta_hosts);
30901da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
30911da177e4SLinus Torvalds 		do {
30921da177e4SLinus Torvalds 			sdebug_remove_adapter();
30931da177e4SLinus Torvalds 		} while (++delta_hosts);
30941da177e4SLinus Torvalds 	}
30951da177e4SLinus Torvalds 	return count;
30961da177e4SLinus Torvalds }
30971da177e4SLinus Torvalds DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
30981da177e4SLinus Torvalds 	    sdebug_add_host_store);
30991da177e4SLinus Torvalds 
310023183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
310123183910SDouglas Gilbert 					  char * buf)
310223183910SDouglas Gilbert {
310323183910SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
310423183910SDouglas Gilbert }
310523183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
310623183910SDouglas Gilbert 					   const char * buf, size_t count)
310723183910SDouglas Gilbert {
310823183910SDouglas Gilbert 	int n;
310923183910SDouglas Gilbert 
311023183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
311123183910SDouglas Gilbert 		scsi_debug_vpd_use_hostno = n;
311223183910SDouglas Gilbert 		return count;
311323183910SDouglas Gilbert 	}
311423183910SDouglas Gilbert 	return -EINVAL;
311523183910SDouglas Gilbert }
311623183910SDouglas Gilbert DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
311723183910SDouglas Gilbert 	    sdebug_vpd_use_hostno_store);
311823183910SDouglas Gilbert 
3119597136abSMartin K. Petersen static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf)
3120597136abSMartin K. Petersen {
3121597136abSMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
3122597136abSMartin K. Petersen }
3123597136abSMartin K. Petersen DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL);
3124597136abSMartin K. Petersen 
3125c6a44287SMartin K. Petersen static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf)
3126c6a44287SMartin K. Petersen {
3127c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
3128c6a44287SMartin K. Petersen }
3129c6a44287SMartin K. Petersen DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL);
3130c6a44287SMartin K. Petersen 
3131c6a44287SMartin K. Petersen static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf)
3132c6a44287SMartin K. Petersen {
3133c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
3134c6a44287SMartin K. Petersen }
3135c6a44287SMartin K. Petersen DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL);
3136c6a44287SMartin K. Petersen 
3137c6a44287SMartin K. Petersen static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf)
3138c6a44287SMartin K. Petersen {
3139c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard);
3140c6a44287SMartin K. Petersen }
3141c6a44287SMartin K. Petersen DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL);
3142c6a44287SMartin K. Petersen 
3143c6a44287SMartin K. Petersen static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf)
3144c6a44287SMartin K. Petersen {
3145c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
3146c6a44287SMartin K. Petersen }
3147c6a44287SMartin K. Petersen DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL);
3148c6a44287SMartin K. Petersen 
314944d92694SMartin K. Petersen static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf)
315044d92694SMartin K. Petersen {
315144d92694SMartin K. Petersen 	ssize_t count;
315244d92694SMartin K. Petersen 
31536014759cSMartin K. Petersen 	if (scsi_debug_tpu == 0 && scsi_debug_tpws == 0)
315444d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
315544d92694SMartin K. Petersen 				 sdebug_store_sectors);
315644d92694SMartin K. Petersen 
315744d92694SMartin K. Petersen 	count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
315844d92694SMartin K. Petersen 
315944d92694SMartin K. Petersen 	buf[count++] = '\n';
316044d92694SMartin K. Petersen 	buf[count++] = 0;
316144d92694SMartin K. Petersen 
316244d92694SMartin K. Petersen 	return count;
316344d92694SMartin K. Petersen }
316444d92694SMartin K. Petersen DRIVER_ATTR(map, S_IRUGO, sdebug_map_show, NULL);
316544d92694SMartin K. Petersen 
3166c6a44287SMartin K. Petersen 
316723183910SDouglas Gilbert /* Note: The following function creates attribute files in the
316823183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
316923183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
317023183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
317123183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
317223183910SDouglas Gilbert  */
31736ecaff7fSRandy Dunlap static int do_create_driverfs_files(void)
31741da177e4SLinus Torvalds {
31756ecaff7fSRandy Dunlap 	int ret;
31766ecaff7fSRandy Dunlap 
31776ecaff7fSRandy Dunlap 	ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
31786ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
31796ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
31806ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
31816ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
318223183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
31836ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
318478d4e5a0SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_queue);
318523183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
318678d4e5a0SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_uld);
31876ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
318823183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
31896ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
31906ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
31916ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
319223183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
319323183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
3194597136abSMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
3195c6a44287SMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix);
3196c6a44287SMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif);
3197c6a44287SMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard);
3198c6a44287SMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato);
319944d92694SMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_map);
32006ecaff7fSRandy Dunlap 	return ret;
32011da177e4SLinus Torvalds }
32021da177e4SLinus Torvalds 
32031da177e4SLinus Torvalds static void do_remove_driverfs_files(void)
32041da177e4SLinus Torvalds {
320544d92694SMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_map);
3206c6a44287SMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato);
3207c6a44287SMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard);
3208c6a44287SMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif);
3209c6a44287SMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix);
3210597136abSMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
321123183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
321223183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
32131da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
32141da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
32151da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
32161da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
321723183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
321878d4e5a0SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_uld);
321923183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
322078d4e5a0SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_queue);
32211da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
322223183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
32231da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
32241da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
32251da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
32261da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
32271da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
32281da177e4SLinus Torvalds }
32291da177e4SLinus Torvalds 
32309b906779SNicholas Bellinger struct device *pseudo_primary;
32318dea0d02SFUJITA Tomonori 
32321da177e4SLinus Torvalds static int __init scsi_debug_init(void)
32331da177e4SLinus Torvalds {
32345f2578e5SFUJITA Tomonori 	unsigned long sz;
32351da177e4SLinus Torvalds 	int host_to_add;
32361da177e4SLinus Torvalds 	int k;
32376ecaff7fSRandy Dunlap 	int ret;
32381da177e4SLinus Torvalds 
3239597136abSMartin K. Petersen 	switch (scsi_debug_sector_size) {
3240597136abSMartin K. Petersen 	case  512:
3241597136abSMartin K. Petersen 	case 1024:
3242597136abSMartin K. Petersen 	case 2048:
3243597136abSMartin K. Petersen 	case 4096:
3244597136abSMartin K. Petersen 		break;
3245597136abSMartin K. Petersen 	default:
3246c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n",
3247597136abSMartin K. Petersen 		       scsi_debug_sector_size);
3248597136abSMartin K. Petersen 		return -EINVAL;
3249597136abSMartin K. Petersen 	}
3250597136abSMartin K. Petersen 
3251c6a44287SMartin K. Petersen 	switch (scsi_debug_dif) {
3252c6a44287SMartin K. Petersen 
3253c6a44287SMartin K. Petersen 	case SD_DIF_TYPE0_PROTECTION:
3254c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
3255395cef03SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
3256c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
3257c6a44287SMartin K. Petersen 		break;
3258c6a44287SMartin K. Petersen 
3259c6a44287SMartin K. Petersen 	default:
3260395cef03SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n");
3261c6a44287SMartin K. Petersen 		return -EINVAL;
3262c6a44287SMartin K. Petersen 	}
3263c6a44287SMartin K. Petersen 
3264c6a44287SMartin K. Petersen 	if (scsi_debug_guard > 1) {
3265c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n");
3266c6a44287SMartin K. Petersen 		return -EINVAL;
3267c6a44287SMartin K. Petersen 	}
3268c6a44287SMartin K. Petersen 
3269c6a44287SMartin K. Petersen 	if (scsi_debug_ato > 1) {
3270c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n");
3271c6a44287SMartin K. Petersen 		return -EINVAL;
3272c6a44287SMartin K. Petersen 	}
3273c6a44287SMartin K. Petersen 
3274ea61fca5SMartin K. Petersen 	if (scsi_debug_physblk_exp > 15) {
3275ea61fca5SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n",
3276ea61fca5SMartin K. Petersen 		       scsi_debug_physblk_exp);
3277ea61fca5SMartin K. Petersen 		return -EINVAL;
3278ea61fca5SMartin K. Petersen 	}
3279ea61fca5SMartin K. Petersen 
3280ea61fca5SMartin K. Petersen 	if (scsi_debug_lowest_aligned > 0x3fff) {
3281ea61fca5SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n",
3282ea61fca5SMartin K. Petersen 		       scsi_debug_lowest_aligned);
3283ea61fca5SMartin K. Petersen 		return -EINVAL;
3284ea61fca5SMartin K. Petersen 	}
3285ea61fca5SMartin K. Petersen 
32861da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb < 1)
32871da177e4SLinus Torvalds 		scsi_debug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
32885f2578e5SFUJITA Tomonori 	sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
3289597136abSMartin K. Petersen 	sdebug_store_sectors = sz / scsi_debug_sector_size;
329028898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
32911da177e4SLinus Torvalds 
32921da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
32931da177e4SLinus Torvalds 	sdebug_heads = 8;
32941da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
32951da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb >= 16)
32961da177e4SLinus Torvalds 		sdebug_heads = 32;
32971da177e4SLinus Torvalds 	else if (scsi_debug_dev_size_mb >= 256)
32981da177e4SLinus Torvalds 		sdebug_heads = 64;
32991da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
33001da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
33011da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
33021da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
33031da177e4SLinus Torvalds 		sdebug_heads = 255;
33041da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
33051da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
33061da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
33071da177e4SLinus Torvalds 	}
33081da177e4SLinus Torvalds 
33091da177e4SLinus Torvalds 	fake_storep = vmalloc(sz);
33101da177e4SLinus Torvalds 	if (NULL == fake_storep) {
33111da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
33121da177e4SLinus Torvalds 		return -ENOMEM;
33131da177e4SLinus Torvalds 	}
33141da177e4SLinus Torvalds 	memset(fake_storep, 0, sz);
33151da177e4SLinus Torvalds 	if (scsi_debug_num_parts > 0)
3316f58b0efbSFUJITA Tomonori 		sdebug_build_parts(fake_storep, sz);
33171da177e4SLinus Torvalds 
3318c6a44287SMartin K. Petersen 	if (scsi_debug_dif) {
3319c6a44287SMartin K. Petersen 		int dif_size;
3320c6a44287SMartin K. Petersen 
3321c6a44287SMartin K. Petersen 		dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
3322c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
3323c6a44287SMartin K. Petersen 
3324c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n",
3325c6a44287SMartin K. Petersen 		       dif_size, dif_storep);
3326c6a44287SMartin K. Petersen 
3327c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
3328c6a44287SMartin K. Petersen 			printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n");
3329c6a44287SMartin K. Petersen 			ret = -ENOMEM;
3330c6a44287SMartin K. Petersen 			goto free_vm;
3331c6a44287SMartin K. Petersen 		}
3332c6a44287SMartin K. Petersen 
3333c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
3334c6a44287SMartin K. Petersen 	}
3335c6a44287SMartin K. Petersen 
33366014759cSMartin K. Petersen 	/* Thin Provisioning */
33376014759cSMartin K. Petersen 	if (scsi_debug_tpu || scsi_debug_tpws) {
333844d92694SMartin K. Petersen 		unsigned int map_bytes;
333944d92694SMartin K. Petersen 
33406014759cSMartin K. Petersen 		scsi_debug_unmap_max_blocks =
33416014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU);
33426014759cSMartin K. Petersen 
33436014759cSMartin K. Petersen 		scsi_debug_unmap_max_desc =
33446014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_max_desc, 0U, 256U);
33456014759cSMartin K. Petersen 
33466014759cSMartin K. Petersen 		scsi_debug_unmap_granularity =
33476014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU);
33486014759cSMartin K. Petersen 
33496014759cSMartin K. Petersen 		if (scsi_debug_unmap_alignment &&
33506014759cSMartin K. Petersen 		    scsi_debug_unmap_granularity < scsi_debug_unmap_alignment) {
335144d92694SMartin K. Petersen 			printk(KERN_ERR
335244d92694SMartin K. Petersen 			       "%s: ERR: unmap_granularity < unmap_alignment\n",
335344d92694SMartin K. Petersen 			       __func__);
335444d92694SMartin K. Petersen 			return -EINVAL;
335544d92694SMartin K. Petersen 		}
335644d92694SMartin K. Petersen 
335744d92694SMartin K. Petersen 		map_size = (sdebug_store_sectors / scsi_debug_unmap_granularity);
335844d92694SMartin K. Petersen 		map_bytes = map_size >> 3;
335944d92694SMartin K. Petersen 		map_storep = vmalloc(map_bytes);
336044d92694SMartin K. Petersen 
336144d92694SMartin K. Petersen 		printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n",
336244d92694SMartin K. Petersen 		       map_size);
336344d92694SMartin K. Petersen 
336444d92694SMartin K. Petersen 		if (map_storep == NULL) {
336544d92694SMartin K. Petersen 			printk(KERN_ERR "scsi_debug_init: out of mem. (MAP)\n");
336644d92694SMartin K. Petersen 			ret = -ENOMEM;
336744d92694SMartin K. Petersen 			goto free_vm;
336844d92694SMartin K. Petersen 		}
336944d92694SMartin K. Petersen 
337044d92694SMartin K. Petersen 		memset(map_storep, 0x0, map_bytes);
337144d92694SMartin K. Petersen 
337244d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
337344d92694SMartin K. Petersen 		if (scsi_debug_num_parts)
337444d92694SMartin K. Petersen 			map_region(0, 2);
337544d92694SMartin K. Petersen 	}
337644d92694SMartin K. Petersen 
33779b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
33789b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
33799b906779SNicholas Bellinger 		printk(KERN_WARNING "scsi_debug: root_device_register() error\n");
33809b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
33816ecaff7fSRandy Dunlap 		goto free_vm;
33826ecaff7fSRandy Dunlap 	}
33836ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
33846ecaff7fSRandy Dunlap 	if (ret < 0) {
33856ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
33866ecaff7fSRandy Dunlap 			ret);
33876ecaff7fSRandy Dunlap 		goto dev_unreg;
33886ecaff7fSRandy Dunlap 	}
33896ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
33906ecaff7fSRandy Dunlap 	if (ret < 0) {
33916ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
33926ecaff7fSRandy Dunlap 			ret);
33936ecaff7fSRandy Dunlap 		goto bus_unreg;
33946ecaff7fSRandy Dunlap 	}
33956ecaff7fSRandy Dunlap 	ret = do_create_driverfs_files();
33966ecaff7fSRandy Dunlap 	if (ret < 0) {
33976ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
33986ecaff7fSRandy Dunlap 			ret);
33996ecaff7fSRandy Dunlap 		goto del_files;
34006ecaff7fSRandy Dunlap 	}
34011da177e4SLinus Torvalds 
34026ecaff7fSRandy Dunlap 	init_all_queued();
34031da177e4SLinus Torvalds 
34041da177e4SLinus Torvalds 	host_to_add = scsi_debug_add_host;
34051da177e4SLinus Torvalds         scsi_debug_add_host = 0;
34061da177e4SLinus Torvalds 
34071da177e4SLinus Torvalds         for (k = 0; k < host_to_add; k++) {
34081da177e4SLinus Torvalds                 if (sdebug_add_adapter()) {
34091da177e4SLinus Torvalds                         printk(KERN_ERR "scsi_debug_init: "
34101da177e4SLinus Torvalds                                "sdebug_add_adapter failed k=%d\n", k);
34111da177e4SLinus Torvalds                         break;
34121da177e4SLinus Torvalds                 }
34131da177e4SLinus Torvalds         }
34141da177e4SLinus Torvalds 
34151da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
34161da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
34171da177e4SLinus Torvalds 		       scsi_debug_add_host);
34181da177e4SLinus Torvalds 	}
34191da177e4SLinus Torvalds 	return 0;
34206ecaff7fSRandy Dunlap 
34216ecaff7fSRandy Dunlap del_files:
34226ecaff7fSRandy Dunlap 	do_remove_driverfs_files();
34236ecaff7fSRandy Dunlap 	driver_unregister(&sdebug_driverfs_driver);
34246ecaff7fSRandy Dunlap bus_unreg:
34256ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
34266ecaff7fSRandy Dunlap dev_unreg:
34279b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
34286ecaff7fSRandy Dunlap free_vm:
342944d92694SMartin K. Petersen 	if (map_storep)
343044d92694SMartin K. Petersen 		vfree(map_storep);
3431c6a44287SMartin K. Petersen 	if (dif_storep)
3432c6a44287SMartin K. Petersen 		vfree(dif_storep);
34336ecaff7fSRandy Dunlap 	vfree(fake_storep);
34346ecaff7fSRandy Dunlap 
34356ecaff7fSRandy Dunlap 	return ret;
34361da177e4SLinus Torvalds }
34371da177e4SLinus Torvalds 
34381da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
34391da177e4SLinus Torvalds {
34401da177e4SLinus Torvalds 	int k = scsi_debug_add_host;
34411da177e4SLinus Torvalds 
34421da177e4SLinus Torvalds 	stop_all_queued();
34431da177e4SLinus Torvalds 	for (; k; k--)
34441da177e4SLinus Torvalds 		sdebug_remove_adapter();
34451da177e4SLinus Torvalds 	do_remove_driverfs_files();
34461da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
34471da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
34489b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
34491da177e4SLinus Torvalds 
3450c6a44287SMartin K. Petersen 	if (dif_storep)
3451c6a44287SMartin K. Petersen 		vfree(dif_storep);
3452c6a44287SMartin K. Petersen 
34531da177e4SLinus Torvalds 	vfree(fake_storep);
34541da177e4SLinus Torvalds }
34551da177e4SLinus Torvalds 
34561da177e4SLinus Torvalds device_initcall(scsi_debug_init);
34571da177e4SLinus Torvalds module_exit(scsi_debug_exit);
34581da177e4SLinus Torvalds 
34591da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev)
34601da177e4SLinus Torvalds {
34611da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
34621da177e4SLinus Torvalds 
34631da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
34641da177e4SLinus Torvalds         kfree(sdbg_host);
34651da177e4SLinus Torvalds }
34661da177e4SLinus Torvalds 
34671da177e4SLinus Torvalds static int sdebug_add_adapter(void)
34681da177e4SLinus Torvalds {
34691da177e4SLinus Torvalds 	int k, devs_per_host;
34701da177e4SLinus Torvalds         int error = 0;
34711da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
34728b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
34731da177e4SLinus Torvalds 
347424669f75SJes Sorensen         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
34751da177e4SLinus Torvalds         if (NULL == sdbg_host) {
34761da177e4SLinus Torvalds                 printk(KERN_ERR "%s: out of memory at line %d\n",
3477cadbd4a5SHarvey Harrison                        __func__, __LINE__);
34781da177e4SLinus Torvalds                 return -ENOMEM;
34791da177e4SLinus Torvalds         }
34801da177e4SLinus Torvalds 
34811da177e4SLinus Torvalds         INIT_LIST_HEAD(&sdbg_host->dev_info_list);
34821da177e4SLinus Torvalds 
34831da177e4SLinus Torvalds 	devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
34841da177e4SLinus Torvalds         for (k = 0; k < devs_per_host; k++) {
34855cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
34865cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
34871da177e4SLinus Torvalds                         printk(KERN_ERR "%s: out of memory at line %d\n",
3488cadbd4a5SHarvey Harrison                                __func__, __LINE__);
34891da177e4SLinus Torvalds                         error = -ENOMEM;
34901da177e4SLinus Torvalds 			goto clean;
34911da177e4SLinus Torvalds                 }
34921da177e4SLinus Torvalds         }
34931da177e4SLinus Torvalds 
34941da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
34951da177e4SLinus Torvalds         list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
34961da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
34971da177e4SLinus Torvalds 
34981da177e4SLinus Torvalds         sdbg_host->dev.bus = &pseudo_lld_bus;
34999b906779SNicholas Bellinger         sdbg_host->dev.parent = pseudo_primary;
35001da177e4SLinus Torvalds         sdbg_host->dev.release = &sdebug_release_adapter;
350171610f55SKay Sievers         dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
35021da177e4SLinus Torvalds 
35031da177e4SLinus Torvalds         error = device_register(&sdbg_host->dev);
35041da177e4SLinus Torvalds 
35051da177e4SLinus Torvalds         if (error)
35061da177e4SLinus Torvalds 		goto clean;
35071da177e4SLinus Torvalds 
35081da177e4SLinus Torvalds 	++scsi_debug_add_host;
35091da177e4SLinus Torvalds         return error;
35101da177e4SLinus Torvalds 
35111da177e4SLinus Torvalds clean:
35128b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
35138b40228fSFUJITA Tomonori 				 dev_list) {
35141da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
35151da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
35161da177e4SLinus Torvalds 	}
35171da177e4SLinus Torvalds 
35181da177e4SLinus Torvalds 	kfree(sdbg_host);
35191da177e4SLinus Torvalds         return error;
35201da177e4SLinus Torvalds }
35211da177e4SLinus Torvalds 
35221da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
35231da177e4SLinus Torvalds {
35241da177e4SLinus Torvalds         struct sdebug_host_info * sdbg_host = NULL;
35251da177e4SLinus Torvalds 
35261da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
35271da177e4SLinus Torvalds         if (!list_empty(&sdebug_host_list)) {
35281da177e4SLinus Torvalds                 sdbg_host = list_entry(sdebug_host_list.prev,
35291da177e4SLinus Torvalds                                        struct sdebug_host_info, host_list);
35301da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
35311da177e4SLinus Torvalds 	}
35321da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
35331da177e4SLinus Torvalds 
35341da177e4SLinus Torvalds 	if (!sdbg_host)
35351da177e4SLinus Torvalds 		return;
35361da177e4SLinus Torvalds 
35371da177e4SLinus Torvalds         device_unregister(&sdbg_host->dev);
35381da177e4SLinus Torvalds         --scsi_debug_add_host;
35391da177e4SLinus Torvalds }
35401da177e4SLinus Torvalds 
3541639db475SFUJITA Tomonori static
3542f281233dSJeff Garzik int scsi_debug_queuecommand_lck(struct scsi_cmnd *SCpnt, done_funct_t done)
3543639db475SFUJITA Tomonori {
3544639db475SFUJITA Tomonori 	unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
3545639db475SFUJITA Tomonori 	int len, k;
3546639db475SFUJITA Tomonori 	unsigned int num;
3547639db475SFUJITA Tomonori 	unsigned long long lba;
3548395cef03SMartin K. Petersen 	u32 ei_lba;
3549639db475SFUJITA Tomonori 	int errsts = 0;
3550639db475SFUJITA Tomonori 	int target = SCpnt->device->id;
3551639db475SFUJITA Tomonori 	struct sdebug_dev_info *devip = NULL;
3552639db475SFUJITA Tomonori 	int inj_recovered = 0;
3553639db475SFUJITA Tomonori 	int inj_transport = 0;
3554c6a44287SMartin K. Petersen 	int inj_dif = 0;
3555c6a44287SMartin K. Petersen 	int inj_dix = 0;
3556639db475SFUJITA Tomonori 	int delay_override = 0;
355744d92694SMartin K. Petersen 	int unmap = 0;
3558639db475SFUJITA Tomonori 
3559639db475SFUJITA Tomonori 	scsi_set_resid(SCpnt, 0);
3560639db475SFUJITA Tomonori 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
3561639db475SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: cmd ");
3562639db475SFUJITA Tomonori 		for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
3563639db475SFUJITA Tomonori 			printk("%02x ", (int)cmd[k]);
3564639db475SFUJITA Tomonori 		printk("\n");
3565639db475SFUJITA Tomonori 	}
3566639db475SFUJITA Tomonori 
3567639db475SFUJITA Tomonori 	if (target == SCpnt->device->host->hostt->this_id) {
3568639db475SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: initiator's id used as "
3569639db475SFUJITA Tomonori 		       "target!\n");
3570639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
3571639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
3572639db475SFUJITA Tomonori 	}
3573639db475SFUJITA Tomonori 
3574639db475SFUJITA Tomonori 	if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
3575639db475SFUJITA Tomonori 	    (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
3576639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
3577639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
3578639db475SFUJITA Tomonori 	devip = devInfoReg(SCpnt->device);
3579639db475SFUJITA Tomonori 	if (NULL == devip)
3580639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
3581639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
3582639db475SFUJITA Tomonori 
3583639db475SFUJITA Tomonori 	if ((scsi_debug_every_nth != 0) &&
3584639db475SFUJITA Tomonori 	    (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
3585639db475SFUJITA Tomonori 		scsi_debug_cmnd_count = 0;
3586639db475SFUJITA Tomonori 		if (scsi_debug_every_nth < -1)
3587639db475SFUJITA Tomonori 			scsi_debug_every_nth = -1;
3588639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
3589639db475SFUJITA Tomonori 			return 0; /* ignore command causing timeout */
3590639db475SFUJITA Tomonori 		else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
3591639db475SFUJITA Tomonori 			inj_recovered = 1; /* to reads and writes below */
3592639db475SFUJITA Tomonori 		else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
3593639db475SFUJITA Tomonori 			inj_transport = 1; /* to reads and writes below */
3594c6a44287SMartin K. Petersen 		else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
3595c6a44287SMartin K. Petersen 			inj_dif = 1; /* to reads and writes below */
3596c6a44287SMartin K. Petersen 		else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
3597c6a44287SMartin K. Petersen 			inj_dix = 1; /* to reads and writes below */
3598639db475SFUJITA Tomonori 	}
3599639db475SFUJITA Tomonori 
3600639db475SFUJITA Tomonori 	if (devip->wlun) {
3601639db475SFUJITA Tomonori 		switch (*cmd) {
3602639db475SFUJITA Tomonori 		case INQUIRY:
3603639db475SFUJITA Tomonori 		case REQUEST_SENSE:
3604639db475SFUJITA Tomonori 		case TEST_UNIT_READY:
3605639db475SFUJITA Tomonori 		case REPORT_LUNS:
3606639db475SFUJITA Tomonori 			break;  /* only allowable wlun commands */
3607639db475SFUJITA Tomonori 		default:
3608639db475SFUJITA Tomonori 			if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3609639db475SFUJITA Tomonori 				printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
3610639db475SFUJITA Tomonori 				       "not supported for wlun\n", *cmd);
3611639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3612639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
3613639db475SFUJITA Tomonori 			errsts = check_condition_result;
3614639db475SFUJITA Tomonori 			return schedule_resp(SCpnt, devip, done, errsts,
3615639db475SFUJITA Tomonori 					     0);
3616639db475SFUJITA Tomonori 		}
3617639db475SFUJITA Tomonori 	}
3618639db475SFUJITA Tomonori 
3619639db475SFUJITA Tomonori 	switch (*cmd) {
3620639db475SFUJITA Tomonori 	case INQUIRY:     /* mandatory, ignore unit attention */
3621639db475SFUJITA Tomonori 		delay_override = 1;
3622639db475SFUJITA Tomonori 		errsts = resp_inquiry(SCpnt, target, devip);
3623639db475SFUJITA Tomonori 		break;
3624639db475SFUJITA Tomonori 	case REQUEST_SENSE:	/* mandatory, ignore unit attention */
3625639db475SFUJITA Tomonori 		delay_override = 1;
3626639db475SFUJITA Tomonori 		errsts = resp_requests(SCpnt, devip);
3627639db475SFUJITA Tomonori 		break;
3628639db475SFUJITA Tomonori 	case REZERO_UNIT:	/* actually this is REWIND for SSC */
3629639db475SFUJITA Tomonori 	case START_STOP:
3630639db475SFUJITA Tomonori 		errsts = resp_start_stop(SCpnt, devip);
3631639db475SFUJITA Tomonori 		break;
3632639db475SFUJITA Tomonori 	case ALLOW_MEDIUM_REMOVAL:
3633639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3634639db475SFUJITA Tomonori 		if (errsts)
3635639db475SFUJITA Tomonori 			break;
3636639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3637639db475SFUJITA Tomonori 			printk(KERN_INFO "scsi_debug: Medium removal %s\n",
3638639db475SFUJITA Tomonori 			       cmd[4] ? "inhibited" : "enabled");
3639639db475SFUJITA Tomonori 		break;
3640639db475SFUJITA Tomonori 	case SEND_DIAGNOSTIC:     /* mandatory */
3641639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3642639db475SFUJITA Tomonori 		break;
3643639db475SFUJITA Tomonori 	case TEST_UNIT_READY:     /* mandatory */
3644639db475SFUJITA Tomonori 		delay_override = 1;
3645639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3646639db475SFUJITA Tomonori 		break;
3647639db475SFUJITA Tomonori 	case RESERVE:
3648639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3649639db475SFUJITA Tomonori 		break;
3650639db475SFUJITA Tomonori 	case RESERVE_10:
3651639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3652639db475SFUJITA Tomonori 		break;
3653639db475SFUJITA Tomonori 	case RELEASE:
3654639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3655639db475SFUJITA Tomonori 		break;
3656639db475SFUJITA Tomonori 	case RELEASE_10:
3657639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3658639db475SFUJITA Tomonori 		break;
3659639db475SFUJITA Tomonori 	case READ_CAPACITY:
3660639db475SFUJITA Tomonori 		errsts = resp_readcap(SCpnt, devip);
3661639db475SFUJITA Tomonori 		break;
3662639db475SFUJITA Tomonori 	case SERVICE_ACTION_IN:
366344d92694SMartin K. Petersen 		if (cmd[1] == SAI_READ_CAPACITY_16)
366444d92694SMartin K. Petersen 			errsts = resp_readcap16(SCpnt, devip);
366544d92694SMartin K. Petersen 		else if (cmd[1] == SAI_GET_LBA_STATUS) {
366644d92694SMartin K. Petersen 
36676014759cSMartin K. Petersen 			if (scsi_debug_tpu == 0 && scsi_debug_tpws == 0) {
366844d92694SMartin K. Petersen 				mk_sense_buffer(devip, ILLEGAL_REQUEST,
366944d92694SMartin K. Petersen 						INVALID_COMMAND_OPCODE, 0);
367044d92694SMartin K. Petersen 				errsts = check_condition_result;
367144d92694SMartin K. Petersen 			} else
367244d92694SMartin K. Petersen 				errsts = resp_get_lba_status(SCpnt, devip);
367344d92694SMartin K. Petersen 		} else {
3674639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3675639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
3676639db475SFUJITA Tomonori 			errsts = check_condition_result;
3677639db475SFUJITA Tomonori 		}
3678639db475SFUJITA Tomonori 		break;
3679639db475SFUJITA Tomonori 	case MAINTENANCE_IN:
3680639db475SFUJITA Tomonori 		if (MI_REPORT_TARGET_PGS != cmd[1]) {
3681639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3682639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
3683639db475SFUJITA Tomonori 			errsts = check_condition_result;
3684639db475SFUJITA Tomonori 			break;
3685639db475SFUJITA Tomonori 		}
3686639db475SFUJITA Tomonori 		errsts = resp_report_tgtpgs(SCpnt, devip);
3687639db475SFUJITA Tomonori 		break;
3688639db475SFUJITA Tomonori 	case READ_16:
3689639db475SFUJITA Tomonori 	case READ_12:
3690639db475SFUJITA Tomonori 	case READ_10:
3691395cef03SMartin K. Petersen 		/* READ{10,12,16} and DIF Type 2 are natural enemies */
3692395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3693395cef03SMartin K. Petersen 		    cmd[1] & 0xe0) {
3694395cef03SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3695395cef03SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
3696395cef03SMartin K. Petersen 			errsts = check_condition_result;
3697395cef03SMartin K. Petersen 			break;
3698395cef03SMartin K. Petersen 		}
3699395cef03SMartin K. Petersen 
3700395cef03SMartin K. Petersen 		if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3701395cef03SMartin K. Petersen 		     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3702395cef03SMartin K. Petersen 		    (cmd[1] & 0xe0) == 0)
3703395cef03SMartin K. Petersen 			printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3704395cef03SMartin K. Petersen 
3705395cef03SMartin K. Petersen 		/* fall through */
3706639db475SFUJITA Tomonori 	case READ_6:
3707395cef03SMartin K. Petersen read:
3708639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3709639db475SFUJITA Tomonori 		if (errsts)
3710639db475SFUJITA Tomonori 			break;
3711639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
3712639db475SFUJITA Tomonori 			break;
3713395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3714395cef03SMartin K. Petersen 		errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
3715639db475SFUJITA Tomonori 		if (inj_recovered && (0 == errsts)) {
3716639db475SFUJITA Tomonori 			mk_sense_buffer(devip, RECOVERED_ERROR,
3717639db475SFUJITA Tomonori 					THRESHOLD_EXCEEDED, 0);
3718639db475SFUJITA Tomonori 			errsts = check_condition_result;
3719639db475SFUJITA Tomonori 		} else if (inj_transport && (0 == errsts)) {
3720639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ABORTED_COMMAND,
3721639db475SFUJITA Tomonori 					TRANSPORT_PROBLEM, ACK_NAK_TO);
3722639db475SFUJITA Tomonori 			errsts = check_condition_result;
3723c6a44287SMartin K. Petersen 		} else if (inj_dif && (0 == errsts)) {
3724c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3725c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3726c6a44287SMartin K. Petersen 		} else if (inj_dix && (0 == errsts)) {
3727c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3728c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3729639db475SFUJITA Tomonori 		}
3730639db475SFUJITA Tomonori 		break;
3731639db475SFUJITA Tomonori 	case REPORT_LUNS:	/* mandatory, ignore unit attention */
3732639db475SFUJITA Tomonori 		delay_override = 1;
3733639db475SFUJITA Tomonori 		errsts = resp_report_luns(SCpnt, devip);
3734639db475SFUJITA Tomonori 		break;
3735639db475SFUJITA Tomonori 	case VERIFY:		/* 10 byte SBC-2 command */
3736639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3737639db475SFUJITA Tomonori 		break;
3738639db475SFUJITA Tomonori 	case WRITE_16:
3739639db475SFUJITA Tomonori 	case WRITE_12:
3740639db475SFUJITA Tomonori 	case WRITE_10:
3741395cef03SMartin K. Petersen 		/* WRITE{10,12,16} and DIF Type 2 are natural enemies */
3742395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3743395cef03SMartin K. Petersen 		    cmd[1] & 0xe0) {
3744395cef03SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3745395cef03SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
3746395cef03SMartin K. Petersen 			errsts = check_condition_result;
3747395cef03SMartin K. Petersen 			break;
3748395cef03SMartin K. Petersen 		}
3749395cef03SMartin K. Petersen 
3750395cef03SMartin K. Petersen 		if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3751395cef03SMartin K. Petersen 		     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3752395cef03SMartin K. Petersen 		    (cmd[1] & 0xe0) == 0)
3753395cef03SMartin K. Petersen 			printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3754395cef03SMartin K. Petersen 
3755395cef03SMartin K. Petersen 		/* fall through */
3756639db475SFUJITA Tomonori 	case WRITE_6:
3757395cef03SMartin K. Petersen write:
3758639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3759639db475SFUJITA Tomonori 		if (errsts)
3760639db475SFUJITA Tomonori 			break;
3761639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
3762639db475SFUJITA Tomonori 			break;
3763395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3764395cef03SMartin K. Petersen 		errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
3765639db475SFUJITA Tomonori 		if (inj_recovered && (0 == errsts)) {
3766639db475SFUJITA Tomonori 			mk_sense_buffer(devip, RECOVERED_ERROR,
3767639db475SFUJITA Tomonori 					THRESHOLD_EXCEEDED, 0);
3768639db475SFUJITA Tomonori 			errsts = check_condition_result;
3769c6a44287SMartin K. Petersen 		} else if (inj_dif && (0 == errsts)) {
3770c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3771c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3772c6a44287SMartin K. Petersen 		} else if (inj_dix && (0 == errsts)) {
3773c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3774c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3775639db475SFUJITA Tomonori 		}
3776639db475SFUJITA Tomonori 		break;
377744d92694SMartin K. Petersen 	case WRITE_SAME_16:
37786014759cSMartin K. Petersen 		if (cmd[1] & 0x8) {
37796014759cSMartin K. Petersen 			if (scsi_debug_tpws == 0) {
37806014759cSMartin K. Petersen 				mk_sense_buffer(devip, ILLEGAL_REQUEST,
37816014759cSMartin K. Petersen 						INVALID_FIELD_IN_CDB, 0);
37826014759cSMartin K. Petersen 				errsts = check_condition_result;
37836014759cSMartin K. Petersen 			} else
378444d92694SMartin K. Petersen 				unmap = 1;
37856014759cSMartin K. Petersen 		}
37866014759cSMartin K. Petersen 		if (errsts)
37876014759cSMartin K. Petersen 			break;
378844d92694SMartin K. Petersen 		/* fall through */
378944d92694SMartin K. Petersen 	case WRITE_SAME:
379044d92694SMartin K. Petersen 		errsts = check_readiness(SCpnt, 0, devip);
379144d92694SMartin K. Petersen 		if (errsts)
379244d92694SMartin K. Petersen 			break;
379344d92694SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
379444d92694SMartin K. Petersen 		errsts = resp_write_same(SCpnt, lba, num, devip, ei_lba, unmap);
379544d92694SMartin K. Petersen 		break;
379644d92694SMartin K. Petersen 	case UNMAP:
379744d92694SMartin K. Petersen 		errsts = check_readiness(SCpnt, 0, devip);
379844d92694SMartin K. Petersen 		if (errsts)
379944d92694SMartin K. Petersen 			break;
380044d92694SMartin K. Petersen 
38016014759cSMartin K. Petersen 		if (scsi_debug_unmap_max_desc == 0 || scsi_debug_tpu == 0) {
380244d92694SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
380344d92694SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
380444d92694SMartin K. Petersen 			errsts = check_condition_result;
380544d92694SMartin K. Petersen 		} else
380644d92694SMartin K. Petersen 			errsts = resp_unmap(SCpnt, devip);
380744d92694SMartin K. Petersen 		break;
3808639db475SFUJITA Tomonori 	case MODE_SENSE:
3809639db475SFUJITA Tomonori 	case MODE_SENSE_10:
3810639db475SFUJITA Tomonori 		errsts = resp_mode_sense(SCpnt, target, devip);
3811639db475SFUJITA Tomonori 		break;
3812639db475SFUJITA Tomonori 	case MODE_SELECT:
3813639db475SFUJITA Tomonori 		errsts = resp_mode_select(SCpnt, 1, devip);
3814639db475SFUJITA Tomonori 		break;
3815639db475SFUJITA Tomonori 	case MODE_SELECT_10:
3816639db475SFUJITA Tomonori 		errsts = resp_mode_select(SCpnt, 0, devip);
3817639db475SFUJITA Tomonori 		break;
3818639db475SFUJITA Tomonori 	case LOG_SENSE:
3819639db475SFUJITA Tomonori 		errsts = resp_log_sense(SCpnt, devip);
3820639db475SFUJITA Tomonori 		break;
3821639db475SFUJITA Tomonori 	case SYNCHRONIZE_CACHE:
3822639db475SFUJITA Tomonori 		delay_override = 1;
3823639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3824639db475SFUJITA Tomonori 		break;
3825639db475SFUJITA Tomonori 	case WRITE_BUFFER:
3826639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3827639db475SFUJITA Tomonori 		break;
3828639db475SFUJITA Tomonori 	case XDWRITEREAD_10:
3829639db475SFUJITA Tomonori 		if (!scsi_bidi_cmnd(SCpnt)) {
3830639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3831639db475SFUJITA Tomonori 					INVALID_FIELD_IN_CDB, 0);
3832639db475SFUJITA Tomonori 			errsts = check_condition_result;
3833639db475SFUJITA Tomonori 			break;
3834639db475SFUJITA Tomonori 		}
3835639db475SFUJITA Tomonori 
3836639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3837639db475SFUJITA Tomonori 		if (errsts)
3838639db475SFUJITA Tomonori 			break;
3839639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
3840639db475SFUJITA Tomonori 			break;
3841395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3842395cef03SMartin K. Petersen 		errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
3843639db475SFUJITA Tomonori 		if (errsts)
3844639db475SFUJITA Tomonori 			break;
3845395cef03SMartin K. Petersen 		errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
3846639db475SFUJITA Tomonori 		if (errsts)
3847639db475SFUJITA Tomonori 			break;
3848639db475SFUJITA Tomonori 		errsts = resp_xdwriteread(SCpnt, lba, num, devip);
3849639db475SFUJITA Tomonori 		break;
3850395cef03SMartin K. Petersen 	case VARIABLE_LENGTH_CMD:
3851395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
3852395cef03SMartin K. Petersen 
3853395cef03SMartin K. Petersen 			if ((cmd[10] & 0xe0) == 0)
3854395cef03SMartin K. Petersen 				printk(KERN_ERR
3855395cef03SMartin K. Petersen 				       "Unprotected RD/WR to DIF device\n");
3856395cef03SMartin K. Petersen 
3857395cef03SMartin K. Petersen 			if (cmd[9] == READ_32) {
3858395cef03SMartin K. Petersen 				BUG_ON(SCpnt->cmd_len < 32);
3859395cef03SMartin K. Petersen 				goto read;
3860395cef03SMartin K. Petersen 			}
3861395cef03SMartin K. Petersen 
3862395cef03SMartin K. Petersen 			if (cmd[9] == WRITE_32) {
3863395cef03SMartin K. Petersen 				BUG_ON(SCpnt->cmd_len < 32);
3864395cef03SMartin K. Petersen 				goto write;
3865395cef03SMartin K. Petersen 			}
3866395cef03SMartin K. Petersen 		}
3867395cef03SMartin K. Petersen 
3868395cef03SMartin K. Petersen 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
3869395cef03SMartin K. Petersen 				INVALID_FIELD_IN_CDB, 0);
3870395cef03SMartin K. Petersen 		errsts = check_condition_result;
3871395cef03SMartin K. Petersen 		break;
3872395cef03SMartin K. Petersen 
3873639db475SFUJITA Tomonori 	default:
3874639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3875639db475SFUJITA Tomonori 			printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
3876639db475SFUJITA Tomonori 			       "supported\n", *cmd);
3877639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3878639db475SFUJITA Tomonori 		if (errsts)
3879639db475SFUJITA Tomonori 			break;	/* Unit attention takes precedence */
3880639db475SFUJITA Tomonori 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
3881639db475SFUJITA Tomonori 		errsts = check_condition_result;
3882639db475SFUJITA Tomonori 		break;
3883639db475SFUJITA Tomonori 	}
3884639db475SFUJITA Tomonori 	return schedule_resp(SCpnt, devip, done, errsts,
3885639db475SFUJITA Tomonori 			     (delay_override ? 0 : scsi_debug_delay));
3886639db475SFUJITA Tomonori }
3887639db475SFUJITA Tomonori 
3888f281233dSJeff Garzik static DEF_SCSI_QCMD(scsi_debug_queuecommand)
3889f281233dSJeff Garzik 
38909e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
38919e603ca0SFUJITA Tomonori 	.proc_info =		scsi_debug_proc_info,
38929e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
38939e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
38949e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
38959e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
38969e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
38979e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
38989e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
38999e603ca0SFUJITA Tomonori 	.queuecommand =		scsi_debug_queuecommand,
39009e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
39019e603ca0SFUJITA Tomonori 	.eh_bus_reset_handler = scsi_debug_bus_reset,
39029e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
39039e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
39049e603ca0SFUJITA Tomonori 	.bios_param =		scsi_debug_biosparam,
39059e603ca0SFUJITA Tomonori 	.can_queue =		SCSI_DEBUG_CANQUEUE,
39069e603ca0SFUJITA Tomonori 	.this_id =		7,
39079e603ca0SFUJITA Tomonori 	.sg_tablesize =		256,
39089e603ca0SFUJITA Tomonori 	.cmd_per_lun =		16,
39099e603ca0SFUJITA Tomonori 	.max_sectors =		0xffff,
39109e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
39119e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
39129e603ca0SFUJITA Tomonori };
39139e603ca0SFUJITA Tomonori 
39141da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev)
39151da177e4SLinus Torvalds {
39161da177e4SLinus Torvalds         int error = 0;
39171da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
39181da177e4SLinus Torvalds         struct Scsi_Host *hpnt;
3919c6a44287SMartin K. Petersen 	int host_prot;
39201da177e4SLinus Torvalds 
39211da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
39221da177e4SLinus Torvalds 
392378d4e5a0SDouglas Gilbert 	sdebug_driver_template.can_queue = scsi_debug_max_queue;
39241da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
39251da177e4SLinus Torvalds 	if (NULL == hpnt) {
3926cadbd4a5SHarvey Harrison 		printk(KERN_ERR "%s: scsi_register failed\n", __func__);
39271da177e4SLinus Torvalds 		error = -ENODEV;
39281da177e4SLinus Torvalds 		return error;
39291da177e4SLinus Torvalds 	}
39301da177e4SLinus Torvalds 
39311da177e4SLinus Torvalds         sdbg_host->shost = hpnt;
39321da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
39331da177e4SLinus Torvalds 	if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
39341da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts + 1;
39351da177e4SLinus Torvalds 	else
39361da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts;
3937c65b1445SDouglas Gilbert 	hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;	/* = scsi_debug_max_luns; */
39381da177e4SLinus Torvalds 
3939c6a44287SMartin K. Petersen 	host_prot = 0;
3940c6a44287SMartin K. Petersen 
3941c6a44287SMartin K. Petersen 	switch (scsi_debug_dif) {
3942c6a44287SMartin K. Petersen 
3943c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
3944c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE1_PROTECTION;
3945c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
3946c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE1_PROTECTION;
3947c6a44287SMartin K. Petersen 		break;
3948c6a44287SMartin K. Petersen 
3949c6a44287SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
3950c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE2_PROTECTION;
3951c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
3952c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE2_PROTECTION;
3953c6a44287SMartin K. Petersen 		break;
3954c6a44287SMartin K. Petersen 
3955c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
3956c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE3_PROTECTION;
3957c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
3958c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE3_PROTECTION;
3959c6a44287SMartin K. Petersen 		break;
3960c6a44287SMartin K. Petersen 
3961c6a44287SMartin K. Petersen 	default:
3962c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
3963c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE0_PROTECTION;
3964c6a44287SMartin K. Petersen 		break;
3965c6a44287SMartin K. Petersen 	}
3966c6a44287SMartin K. Petersen 
3967c6a44287SMartin K. Petersen 	scsi_host_set_prot(hpnt, host_prot);
3968c6a44287SMartin K. Petersen 
3969c6a44287SMartin K. Petersen 	printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
3970c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
3971c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
3972c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
3973c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
3974c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
3975c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
3976c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
3977c6a44287SMartin K. Petersen 
3978c6a44287SMartin K. Petersen 	if (scsi_debug_guard == 1)
3979c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
3980c6a44287SMartin K. Petersen 	else
3981c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
3982c6a44287SMartin K. Petersen 
39831da177e4SLinus Torvalds         error = scsi_add_host(hpnt, &sdbg_host->dev);
39841da177e4SLinus Torvalds         if (error) {
3985cadbd4a5SHarvey Harrison                 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
39861da177e4SLinus Torvalds                 error = -ENODEV;
39871da177e4SLinus Torvalds 		scsi_host_put(hpnt);
39881da177e4SLinus Torvalds         } else
39891da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
39901da177e4SLinus Torvalds 
39911da177e4SLinus Torvalds 
39921da177e4SLinus Torvalds         return error;
39931da177e4SLinus Torvalds }
39941da177e4SLinus Torvalds 
39951da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev)
39961da177e4SLinus Torvalds {
39971da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
39988b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
39991da177e4SLinus Torvalds 
40001da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
40011da177e4SLinus Torvalds 
40021da177e4SLinus Torvalds 	if (!sdbg_host) {
40031da177e4SLinus Torvalds 		printk(KERN_ERR "%s: Unable to locate host info\n",
4004cadbd4a5SHarvey Harrison 		       __func__);
40051da177e4SLinus Torvalds 		return -ENODEV;
40061da177e4SLinus Torvalds 	}
40071da177e4SLinus Torvalds 
40081da177e4SLinus Torvalds         scsi_remove_host(sdbg_host->shost);
40091da177e4SLinus Torvalds 
40108b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
40118b40228fSFUJITA Tomonori 				 dev_list) {
40121da177e4SLinus Torvalds                 list_del(&sdbg_devinfo->dev_list);
40131da177e4SLinus Torvalds                 kfree(sdbg_devinfo);
40141da177e4SLinus Torvalds         }
40151da177e4SLinus Torvalds 
40161da177e4SLinus Torvalds         scsi_host_put(sdbg_host->shost);
40171da177e4SLinus Torvalds         return 0;
40181da177e4SLinus Torvalds }
40191da177e4SLinus Torvalds 
40208dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
40218dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
40221da177e4SLinus Torvalds {
40238dea0d02SFUJITA Tomonori 	return 1;
40248dea0d02SFUJITA Tomonori }
40251da177e4SLinus Torvalds 
40268dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
40278dea0d02SFUJITA Tomonori 	.name = "pseudo",
40288dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
40298dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
40308dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
40318dea0d02SFUJITA Tomonori };
4032