xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision c5af0db9)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
31da177e4SLinus Torvalds  *  Copyright (C) 1992  Eric Youngdale
41da177e4SLinus Torvalds  *  Simulate a host adapter with 2 disks attached.  Do a lot of checking
51da177e4SLinus Torvalds  *  to make sure that we are not getting blocks mixed up, and PANIC if
61da177e4SLinus Torvalds  *  anything out of the ordinary is seen.
71da177e4SLinus Torvalds  * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *  This version is more generic, simulating a variable number of disk
1023183910SDouglas Gilbert  *  (or disk like devices) sharing a common amount of RAM. To be more
1123183910SDouglas Gilbert  *  realistic, the simulated devices have the transport attributes of
1223183910SDouglas Gilbert  *  SAS disks.
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  *
1578d4e5a0SDouglas Gilbert  *  For documentation see http://sg.danny.cz/sg/sdebug26.html
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  *   D. Gilbert (dpg) work for Magneto-Optical device test [20010421]
181da177e4SLinus Torvalds  *   dpg: work for devfs large number of disks [20010809]
191da177e4SLinus Torvalds  *        forked for lk 2.5 series [20011216, 20020101]
201da177e4SLinus Torvalds  *        use vmalloc() more inquiry+mode_sense [20020302]
211da177e4SLinus Torvalds  *        add timers for delayed responses [20020721]
221da177e4SLinus Torvalds  *   Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031]
231da177e4SLinus Torvalds  *   Mike Anderson <andmike@us.ibm.com> sysfs work [20021118]
241da177e4SLinus Torvalds  *   dpg: change style of boot options to "scsi_debug.num_tgts=2" and
251da177e4SLinus Torvalds  *        module options to "modprobe scsi_debug num_tgts=2" [20021221]
261da177e4SLinus Torvalds  */
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds #include <linux/module.h>
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds #include <linux/kernel.h>
311da177e4SLinus Torvalds #include <linux/errno.h>
321da177e4SLinus Torvalds #include <linux/timer.h>
335a0e3ad6STejun Heo #include <linux/slab.h>
341da177e4SLinus Torvalds #include <linux/types.h>
351da177e4SLinus Torvalds #include <linux/string.h>
361da177e4SLinus Torvalds #include <linux/genhd.h>
371da177e4SLinus Torvalds #include <linux/fs.h>
381da177e4SLinus Torvalds #include <linux/init.h>
391da177e4SLinus Torvalds #include <linux/proc_fs.h>
401da177e4SLinus Torvalds #include <linux/vmalloc.h>
411da177e4SLinus Torvalds #include <linux/moduleparam.h>
42852e034dSJens Axboe #include <linux/scatterlist.h>
431da177e4SLinus Torvalds #include <linux/blkdev.h>
44c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h>
45c6a44287SMartin K. Petersen 
46c6a44287SMartin K. Petersen #include <net/checksum.h>
479ff26eefSFUJITA Tomonori 
4844d92694SMartin K. Petersen #include <asm/unaligned.h>
4944d92694SMartin K. Petersen 
509ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
519ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
529ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
531da177e4SLinus Torvalds #include <scsi/scsi_host.h>
541da177e4SLinus Torvalds #include <scsi/scsicam.h>
55a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
56395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
571da177e4SLinus Torvalds 
58c6a44287SMartin K. Petersen #include "sd.h"
591da177e4SLinus Torvalds #include "scsi_logging.h"
601da177e4SLinus Torvalds 
6178d4e5a0SDouglas Gilbert #define SCSI_DEBUG_VERSION "1.82"
6278d4e5a0SDouglas Gilbert static const char * scsi_debug_version_date = "20100324";
631da177e4SLinus Torvalds 
646f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
65c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
66c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
67c5af0db9SAkinobu Mita #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
681da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
69c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
701da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
711da177e4SLinus Torvalds #define ADDR_OUT_OF_RANGE 0x21
72395cef03SMartin K. Petersen #define INVALID_COMMAND_OPCODE 0x20
731da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
74c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
751da177e4SLinus Torvalds #define POWERON_RESET 0x29
761da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
776f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
78c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
79c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
801da177e4SLinus Torvalds 
816f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
826f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
836f3cbf55SDouglas Gilbert 
841da177e4SLinus Torvalds #define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds /* Default values for driver parameters */
871da177e4SLinus Torvalds #define DEF_NUM_HOST   1
881da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
891da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
901da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
911da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
921da177e4SLinus Torvalds  */
935b94e232SMartin K. Petersen #define DEF_ATO 1
941da177e4SLinus Torvalds #define DEF_DELAY   1
951da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
965b94e232SMartin K. Petersen #define DEF_DIF 0
975b94e232SMartin K. Petersen #define DEF_DIX 0
985b94e232SMartin K. Petersen #define DEF_D_SENSE   0
991da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1005b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1015b94e232SMartin K. Petersen #define DEF_GUARD 0
1025b94e232SMartin K. Petersen #define DEF_LBPU 0
1035b94e232SMartin K. Petersen #define DEF_LBPWS 0
1045b94e232SMartin K. Petersen #define DEF_LBPWS10 0
105be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1065b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
1075b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1081da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1091da177e4SLinus Torvalds #define DEF_OPTS   0
110e308b3d1SMartin K. Petersen #define DEF_OPT_BLKS 64
1115b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
1125b94e232SMartin K. Petersen #define DEF_PTYPE   0
113d986788bSMartin Pitt #define DEF_REMOVABLE false
1145b94e232SMartin K. Petersen #define DEF_SCSI_LEVEL   5    /* INQUIRY, byte2 [5->SPC-3] */
1155b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1165b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1175b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1186014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1196014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1205b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1215b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1225b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
1231da177e4SLinus Torvalds 
1241da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */
1251da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE   1
1261da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR   2
1271da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT   4
1281da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR   8
1296f3cbf55SDouglas Gilbert #define SCSI_DEBUG_OPT_TRANSPORT_ERR   16
130c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIF_ERR   32
131c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIX_ERR   64
13218a4d0a2SMartin K. Petersen #define SCSI_DEBUG_OPT_MAC_TIMEOUT  128
1331da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
1341da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1351da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1361da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1376f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1386f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1391da177e4SLinus Torvalds  *
1401da177e4SLinus Torvalds  * When "every_nth" < 0 then after "- every_nth" commands:
1411da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1421da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1431da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1446f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1456f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1461da177e4SLinus Torvalds  * This will continue until some other action occurs (e.g. the user
1471da177e4SLinus Torvalds  * writing a new value (other than -1 or 1) to every_nth via sysfs).
1481da177e4SLinus Torvalds  */
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
1511da177e4SLinus Torvalds  * sector on read commands: */
1521da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
15332f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
1541da177e4SLinus Torvalds 
1551da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
1561da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
1571da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
158c65b1445SDouglas Gilbert #define SAM2_WLUN_REPORT_LUNS 0xc101
1591da177e4SLinus Torvalds 
16078d4e5a0SDouglas Gilbert /* Can queue up to this number of commands. Typically commands that
16178d4e5a0SDouglas Gilbert  * that have a non-zero delay are queued. */
16278d4e5a0SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE  255
16378d4e5a0SDouglas Gilbert 
1641da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST;
1655b94e232SMartin K. Petersen static int scsi_debug_ato = DEF_ATO;
1661da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY;
1671da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
1685b94e232SMartin K. Petersen static int scsi_debug_dif = DEF_DIF;
1695b94e232SMartin K. Petersen static int scsi_debug_dix = DEF_DIX;
1705b94e232SMartin K. Petersen static int scsi_debug_dsense = DEF_D_SENSE;
1711da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH;
1725b94e232SMartin K. Petersen static int scsi_debug_fake_rw = DEF_FAKE_RW;
17368aee7baSAkinobu Mita static unsigned int scsi_debug_guard = DEF_GUARD;
1745b94e232SMartin K. Petersen static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
1751da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS;
17678d4e5a0SDouglas Gilbert static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE;
177c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
1785b94e232SMartin K. Petersen static int scsi_debug_no_uld = 0;
1795b94e232SMartin K. Petersen static int scsi_debug_num_parts = DEF_NUM_PARTS;
1805b94e232SMartin K. Petersen static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
181e308b3d1SMartin K. Petersen static int scsi_debug_opt_blks = DEF_OPT_BLKS;
1825b94e232SMartin K. Petersen static int scsi_debug_opts = DEF_OPTS;
1835b94e232SMartin K. Petersen static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
1845b94e232SMartin K. Petersen static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
1855b94e232SMartin K. Petersen static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
1865b94e232SMartin K. Petersen static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
1875b94e232SMartin K. Petersen static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
1885b94e232SMartin K. Petersen static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
1895b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpu = DEF_LBPU;
1905b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws = DEF_LBPWS;
1915b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10;
192be1dd78dSEric Sandeen static unsigned int scsi_debug_lbprz = DEF_LBPRZ;
1936014759cSMartin K. Petersen static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
1945b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
1955b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
1965b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
1975b94e232SMartin K. Petersen static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH;
198d986788bSMartin Pitt static bool scsi_debug_removable = DEF_REMOVABLE;
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds static int scsi_debug_cmnd_count = 0;
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds #define DEV_READONLY(TGT)      (0)
2031da177e4SLinus Torvalds 
204c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
2051da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
2081da177e4SLinus Torvalds    may still need them */
2091da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
2101da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
2111da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4
2141da177e4SLinus Torvalds 
2151da177e4SLinus Torvalds #define SDEBUG_SENSE_LEN 32
2161da177e4SLinus Torvalds 
217395cef03SMartin K. Petersen #define SCSI_DEBUG_MAX_CMD_LEN 32
2189e603ca0SFUJITA Tomonori 
2195b94e232SMartin K. Petersen static unsigned int scsi_debug_lbp(void)
2205b94e232SMartin K. Petersen {
2215b94e232SMartin K. Petersen 	return scsi_debug_lbpu | scsi_debug_lbpws | scsi_debug_lbpws10;
2225b94e232SMartin K. Petersen }
2235b94e232SMartin K. Petersen 
2241da177e4SLinus Torvalds struct sdebug_dev_info {
2251da177e4SLinus Torvalds 	struct list_head dev_list;
2261da177e4SLinus Torvalds 	unsigned char sense_buff[SDEBUG_SENSE_LEN];	/* weak nexus */
2271da177e4SLinus Torvalds 	unsigned int channel;
2281da177e4SLinus Torvalds 	unsigned int target;
2291da177e4SLinus Torvalds 	unsigned int lun;
2301da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
231c65b1445SDouglas Gilbert 	unsigned int wlun;
2321da177e4SLinus Torvalds 	char reset;
233c65b1445SDouglas Gilbert 	char stopped;
2341da177e4SLinus Torvalds 	char used;
2351da177e4SLinus Torvalds };
2361da177e4SLinus Torvalds 
2371da177e4SLinus Torvalds struct sdebug_host_info {
2381da177e4SLinus Torvalds 	struct list_head host_list;
2391da177e4SLinus Torvalds 	struct Scsi_Host *shost;
2401da177e4SLinus Torvalds 	struct device dev;
2411da177e4SLinus Torvalds 	struct list_head dev_info_list;
2421da177e4SLinus Torvalds };
2431da177e4SLinus Torvalds 
2441da177e4SLinus Torvalds #define to_sdebug_host(d)	\
2451da177e4SLinus Torvalds 	container_of(d, struct sdebug_host_info, dev)
2461da177e4SLinus Torvalds 
2471da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
2481da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
2491da177e4SLinus Torvalds 
2501da177e4SLinus Torvalds typedef void (* done_funct_t) (struct scsi_cmnd *);
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds struct sdebug_queued_cmd {
2531da177e4SLinus Torvalds 	int in_use;
2541da177e4SLinus Torvalds 	struct timer_list cmnd_timer;
2551da177e4SLinus Torvalds 	done_funct_t done_funct;
2561da177e4SLinus Torvalds 	struct scsi_cmnd * a_cmnd;
2571da177e4SLinus Torvalds 	int scsi_result;
2581da177e4SLinus Torvalds };
2591da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
2601da177e4SLinus Torvalds 
2611da177e4SLinus Torvalds static unsigned char * fake_storep;	/* ramdisk storage */
262e18d8beaSAkinobu Mita static struct sd_dif_tuple *dif_storep;	/* protection info */
26344d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
2641da177e4SLinus Torvalds 
26544d92694SMartin K. Petersen static unsigned long map_size;
2661da177e4SLinus Torvalds static int num_aborts = 0;
2671da177e4SLinus Torvalds static int num_dev_resets = 0;
2681da177e4SLinus Torvalds static int num_bus_resets = 0;
2691da177e4SLinus Torvalds static int num_host_resets = 0;
270c6a44287SMartin K. Petersen static int dix_writes;
271c6a44287SMartin K. Petersen static int dix_reads;
272c6a44287SMartin K. Petersen static int dif_errors;
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock);
2751da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
2761da177e4SLinus Torvalds 
2771da177e4SLinus Torvalds static char sdebug_proc_name[] = "scsi_debug";
2781da177e4SLinus Torvalds 
2791da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
2821da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
2831da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
2841da177e4SLinus Torvalds };
2851da177e4SLinus Torvalds 
2861da177e4SLinus Torvalds static const int check_condition_result =
2871da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
2881da177e4SLinus Torvalds 
289c6a44287SMartin K. Petersen static const int illegal_condition_result =
290c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
291c6a44287SMartin K. Petersen 
292c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
293c65b1445SDouglas Gilbert 				    0, 0, 0x2, 0x4b};
294c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
295c65b1445SDouglas Gilbert 			           0, 0, 0x0, 0x0};
296c65b1445SDouglas Gilbert 
29714faa944SAkinobu Mita static void *fake_store(unsigned long long lba)
29814faa944SAkinobu Mita {
29914faa944SAkinobu Mita 	lba = do_div(lba, sdebug_store_sectors);
30014faa944SAkinobu Mita 
30114faa944SAkinobu Mita 	return fake_storep + lba * scsi_debug_sector_size;
30214faa944SAkinobu Mita }
30314faa944SAkinobu Mita 
30414faa944SAkinobu Mita static struct sd_dif_tuple *dif_store(sector_t sector)
30514faa944SAkinobu Mita {
30614faa944SAkinobu Mita 	sector = do_div(sector, sdebug_store_sectors);
30714faa944SAkinobu Mita 
30814faa944SAkinobu Mita 	return dif_storep + sector;
30914faa944SAkinobu Mita }
31014faa944SAkinobu Mita 
3111da177e4SLinus Torvalds static int sdebug_add_adapter(void);
3121da177e4SLinus Torvalds static void sdebug_remove_adapter(void);
3131da177e4SLinus Torvalds 
3148dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
3158dea0d02SFUJITA Tomonori {
3168dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
3178dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
3188dea0d02SFUJITA Tomonori 
3198dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
3208dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3218dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
3228dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
3238dea0d02SFUJITA Tomonori 		    (scsi_debug_num_tgts > hpnt->this_id))
3248dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts + 1;
3258dea0d02SFUJITA Tomonori 		else
3268dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts;
3278dea0d02SFUJITA Tomonori 		/* scsi_debug_max_luns; */
3288dea0d02SFUJITA Tomonori 		hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
3298dea0d02SFUJITA Tomonori 	}
3308dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
3318dea0d02SFUJITA Tomonori }
3328dea0d02SFUJITA Tomonori 
3338dea0d02SFUJITA Tomonori static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
3348dea0d02SFUJITA Tomonori 			    int asc, int asq)
3358dea0d02SFUJITA Tomonori {
3368dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
3378dea0d02SFUJITA Tomonori 
3388dea0d02SFUJITA Tomonori 	sbuff = devip->sense_buff;
3398dea0d02SFUJITA Tomonori 	memset(sbuff, 0, SDEBUG_SENSE_LEN);
3408dea0d02SFUJITA Tomonori 
3418dea0d02SFUJITA Tomonori 	scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
3428dea0d02SFUJITA Tomonori 
3438dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3448dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug:    [sense_key,asc,ascq]: "
3458dea0d02SFUJITA Tomonori 		      "[0x%x,0x%x,0x%x]\n", key, asc, asq);
3468dea0d02SFUJITA Tomonori }
3471da177e4SLinus Torvalds 
3483de9f944SFUJITA Tomonori static void get_data_transfer_info(unsigned char *cmd,
349395cef03SMartin K. Petersen 				   unsigned long long *lba, unsigned int *num,
350395cef03SMartin K. Petersen 				   u32 *ei_lba)
3513de9f944SFUJITA Tomonori {
352395cef03SMartin K. Petersen 	*ei_lba = 0;
353395cef03SMartin K. Petersen 
3543de9f944SFUJITA Tomonori 	switch (*cmd) {
355395cef03SMartin K. Petersen 	case VARIABLE_LENGTH_CMD:
356395cef03SMartin K. Petersen 		*lba = (u64)cmd[19] | (u64)cmd[18] << 8 |
357395cef03SMartin K. Petersen 			(u64)cmd[17] << 16 | (u64)cmd[16] << 24 |
358395cef03SMartin K. Petersen 			(u64)cmd[15] << 32 | (u64)cmd[14] << 40 |
359395cef03SMartin K. Petersen 			(u64)cmd[13] << 48 | (u64)cmd[12] << 56;
360395cef03SMartin K. Petersen 
361395cef03SMartin K. Petersen 		*ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 |
362395cef03SMartin K. Petersen 			(u32)cmd[21] << 16 | (u32)cmd[20] << 24;
363395cef03SMartin K. Petersen 
364395cef03SMartin K. Petersen 		*num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 |
365395cef03SMartin K. Petersen 			(u32)cmd[28] << 24;
366395cef03SMartin K. Petersen 		break;
367395cef03SMartin K. Petersen 
36844d92694SMartin K. Petersen 	case WRITE_SAME_16:
3693de9f944SFUJITA Tomonori 	case WRITE_16:
3703de9f944SFUJITA Tomonori 	case READ_16:
371d5cdc989SFUJITA Tomonori 		*lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
372d5cdc989SFUJITA Tomonori 			(u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
373d5cdc989SFUJITA Tomonori 			(u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
374d5cdc989SFUJITA Tomonori 			(u64)cmd[3] << 48 | (u64)cmd[2] << 56;
375d5cdc989SFUJITA Tomonori 
376d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
377d5cdc989SFUJITA Tomonori 			(u32)cmd[10] << 24;
3783de9f944SFUJITA Tomonori 		break;
3793de9f944SFUJITA Tomonori 	case WRITE_12:
3803de9f944SFUJITA Tomonori 	case READ_12:
381d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
382d5cdc989SFUJITA Tomonori 			(u32)cmd[2] << 24;
383d5cdc989SFUJITA Tomonori 
384d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
385d5cdc989SFUJITA Tomonori 			(u32)cmd[6] << 24;
3863de9f944SFUJITA Tomonori 		break;
38744d92694SMartin K. Petersen 	case WRITE_SAME:
3883de9f944SFUJITA Tomonori 	case WRITE_10:
3893de9f944SFUJITA Tomonori 	case READ_10:
390c639d14eSFUJITA Tomonori 	case XDWRITEREAD_10:
391d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[5] | (u32)cmd[4] << 8 |	(u32)cmd[3] << 16 |
392d5cdc989SFUJITA Tomonori 			(u32)cmd[2] << 24;
393d5cdc989SFUJITA Tomonori 
394d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[8] | (u32)cmd[7] << 8;
3953de9f944SFUJITA Tomonori 		break;
3963de9f944SFUJITA Tomonori 	case WRITE_6:
3973de9f944SFUJITA Tomonori 	case READ_6:
398d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
399d5cdc989SFUJITA Tomonori 			(u32)(cmd[1] & 0x1f) << 16;
4003de9f944SFUJITA Tomonori 		*num = (0 == cmd[4]) ? 256 : cmd[4];
4013de9f944SFUJITA Tomonori 		break;
4023de9f944SFUJITA Tomonori 	default:
4033de9f944SFUJITA Tomonori 		break;
4043de9f944SFUJITA Tomonori 	}
4053de9f944SFUJITA Tomonori }
4061da177e4SLinus Torvalds 
4071da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
4081da177e4SLinus Torvalds {
4091da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
4101da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
4111da177e4SLinus Torvalds 	}
4121da177e4SLinus Torvalds 	return -EINVAL;
4131da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
4141da177e4SLinus Torvalds }
4151da177e4SLinus Torvalds 
416c65b1445SDouglas Gilbert static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
417c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
4181da177e4SLinus Torvalds {
4191da177e4SLinus Torvalds 	if (devip->reset) {
4201da177e4SLinus Torvalds 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
4211da177e4SLinus Torvalds 			printk(KERN_INFO "scsi_debug: Reporting Unit "
4221da177e4SLinus Torvalds 			       "attention: power on reset\n");
4231da177e4SLinus Torvalds 		devip->reset = 0;
4241da177e4SLinus Torvalds 		mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
4251da177e4SLinus Torvalds 		return check_condition_result;
4261da177e4SLinus Torvalds 	}
427c65b1445SDouglas Gilbert 	if ((0 == reset_only) && devip->stopped) {
428c65b1445SDouglas Gilbert 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
429c65b1445SDouglas Gilbert 			printk(KERN_INFO "scsi_debug: Reporting Not "
430c65b1445SDouglas Gilbert 			       "ready: initializing command required\n");
431c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
432c65b1445SDouglas Gilbert 				0x2);
433c65b1445SDouglas Gilbert 		return check_condition_result;
434c65b1445SDouglas Gilbert 	}
4351da177e4SLinus Torvalds 	return 0;
4361da177e4SLinus Torvalds }
4371da177e4SLinus Torvalds 
4381da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
4391da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
4401da177e4SLinus Torvalds 				int arr_len)
4411da177e4SLinus Torvalds {
44221a61829SFUJITA Tomonori 	int act_len;
443072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
4441da177e4SLinus Torvalds 
445072d0bb3SFUJITA Tomonori 	if (!sdb->length)
4461da177e4SLinus Torvalds 		return 0;
447072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
4481da177e4SLinus Torvalds 		return (DID_ERROR << 16);
44921a61829SFUJITA Tomonori 
45021a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
45121a61829SFUJITA Tomonori 				      arr, arr_len);
45221a61829SFUJITA Tomonori 	sdb->resid = scsi_bufflen(scp) - act_len;
45321a61829SFUJITA Tomonori 
4541da177e4SLinus Torvalds 	return 0;
4551da177e4SLinus Torvalds }
4561da177e4SLinus Torvalds 
4571da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */
4581da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
45921a61829SFUJITA Tomonori 			       int arr_len)
4601da177e4SLinus Torvalds {
46121a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
4621da177e4SLinus Torvalds 		return 0;
463072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
4641da177e4SLinus Torvalds 		return -1;
46521a61829SFUJITA Tomonori 
46621a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
4671da177e4SLinus Torvalds }
4681da177e4SLinus Torvalds 
4691da177e4SLinus Torvalds 
4701da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux   ";
4711da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug      ";
4721da177e4SLinus Torvalds static const char * inq_product_rev = "0004";
4731da177e4SLinus Torvalds 
4745a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
4755a09e398SHannes Reinecke 			   int target_dev_id, int dev_id_num,
4765a09e398SHannes Reinecke 			   const char * dev_id_str,
477c65b1445SDouglas Gilbert 			   int dev_id_str_len)
4781da177e4SLinus Torvalds {
479c65b1445SDouglas Gilbert 	int num, port_a;
480c65b1445SDouglas Gilbert 	char b[32];
4811da177e4SLinus Torvalds 
482c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
4831da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
4841da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
4851da177e4SLinus Torvalds 	arr[1] = 0x1;
4861da177e4SLinus Torvalds 	arr[2] = 0x0;
4871da177e4SLinus Torvalds 	memcpy(&arr[4], inq_vendor_id, 8);
4881da177e4SLinus Torvalds 	memcpy(&arr[12], inq_product_id, 16);
4891da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
4901da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
4911da177e4SLinus Torvalds 	arr[3] = num;
4921da177e4SLinus Torvalds 	num += 4;
493c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
494c65b1445SDouglas Gilbert 		/* NAA-5, Logical unit identifier (binary) */
495c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* binary (not necessarily sas) */
496c65b1445SDouglas Gilbert 		arr[num++] = 0x3;	/* PIV=0, lu, naa */
497c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
498c65b1445SDouglas Gilbert 		arr[num++] = 0x8;
499c65b1445SDouglas Gilbert 		arr[num++] = 0x53;  /* naa-5 ieee company id=0x333333 (fake) */
500c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
501c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
502c65b1445SDouglas Gilbert 		arr[num++] = 0x30;
503c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 24);
504c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 16) & 0xff;
505c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 8) & 0xff;
506c65b1445SDouglas Gilbert 		arr[num++] = dev_id_num & 0xff;
507c65b1445SDouglas Gilbert 		/* Target relative port number */
508c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
509c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
510c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
511c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
512c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
513c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
514c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
515c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
516c65b1445SDouglas Gilbert 	}
517c65b1445SDouglas Gilbert 	/* NAA-5, Target port identifier */
518c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
519c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
520c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
521c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
522c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
523c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
524c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
525c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
526c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
527c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
528c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
529c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
5305a09e398SHannes Reinecke 	/* NAA-5, Target port group identifier */
5315a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
5325a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
5335a09e398SHannes Reinecke 	arr[num++] = 0x0;
5345a09e398SHannes Reinecke 	arr[num++] = 0x4;
5355a09e398SHannes Reinecke 	arr[num++] = 0;
5365a09e398SHannes Reinecke 	arr[num++] = 0;
5375a09e398SHannes Reinecke 	arr[num++] = (port_group_id >> 8) & 0xff;
5385a09e398SHannes Reinecke 	arr[num++] = port_group_id & 0xff;
539c65b1445SDouglas Gilbert 	/* NAA-5, Target device identifier */
540c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
541c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
542c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
543c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
544c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
545c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
546c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
547c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
548c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 24);
549c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 16) & 0xff;
550c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 8) & 0xff;
551c65b1445SDouglas Gilbert 	arr[num++] = target_dev_id & 0xff;
552c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
553c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
554c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
555c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
556c65b1445SDouglas Gilbert 	arr[num++] = 24;
557c65b1445SDouglas Gilbert 	memcpy(arr + num, "naa.52222220", 12);
558c65b1445SDouglas Gilbert 	num += 12;
559c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
560c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
561c65b1445SDouglas Gilbert 	num += 8;
562c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
563c65b1445SDouglas Gilbert 	num += 4;
564c65b1445SDouglas Gilbert 	return num;
565c65b1445SDouglas Gilbert }
566c65b1445SDouglas Gilbert 
567c65b1445SDouglas Gilbert 
568c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
569c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
570c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
571c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
572c65b1445SDouglas Gilbert };
573c65b1445SDouglas Gilbert 
574c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr)
575c65b1445SDouglas Gilbert {
576c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
577c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
578c65b1445SDouglas Gilbert }
579c65b1445SDouglas Gilbert 
580c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr)
581c65b1445SDouglas Gilbert {
582c65b1445SDouglas Gilbert 	int num = 0;
583c65b1445SDouglas Gilbert 	const char * na1 = "https://www.kernel.org/config";
584c65b1445SDouglas Gilbert 	const char * na2 = "http://www.kernel.org/log";
585c65b1445SDouglas Gilbert 	int plen, olen;
586c65b1445SDouglas Gilbert 
587c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
588c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
589c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
590c65b1445SDouglas Gilbert 	olen = strlen(na1);
591c65b1445SDouglas Gilbert 	plen = olen + 1;
592c65b1445SDouglas Gilbert 	if (plen % 4)
593c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
594c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
595c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
596c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
597c65b1445SDouglas Gilbert 	num += plen;
598c65b1445SDouglas Gilbert 
599c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
600c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
601c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
602c65b1445SDouglas Gilbert 	olen = strlen(na2);
603c65b1445SDouglas Gilbert 	plen = olen + 1;
604c65b1445SDouglas Gilbert 	if (plen % 4)
605c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
606c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
607c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
608c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
609c65b1445SDouglas Gilbert 	num += plen;
610c65b1445SDouglas Gilbert 
611c65b1445SDouglas Gilbert 	return num;
612c65b1445SDouglas Gilbert }
613c65b1445SDouglas Gilbert 
614c65b1445SDouglas Gilbert /* SCSI ports VPD page */
615c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
616c65b1445SDouglas Gilbert {
617c65b1445SDouglas Gilbert 	int num = 0;
618c65b1445SDouglas Gilbert 	int port_a, port_b;
619c65b1445SDouglas Gilbert 
620c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
621c65b1445SDouglas Gilbert 	port_b = port_a + 1;
622c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
623c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
624c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
625c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
626c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
627c65b1445SDouglas Gilbert 	num += 6;
628c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
629c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
630c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
631c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
632c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
633c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
634c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
635c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
636c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
637c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
638c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
639c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
640c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
641c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
642c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
643c65b1445SDouglas Gilbert 
644c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
645c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
646c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
647c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
648c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
649c65b1445SDouglas Gilbert 	num += 6;
650c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
651c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
652c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
653c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
654c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
655c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
656c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
657c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
658c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
659c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
660c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
661c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 24);
662c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 16) & 0xff;
663c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 8) & 0xff;
664c65b1445SDouglas Gilbert 	arr[num++] = port_b & 0xff;
665c65b1445SDouglas Gilbert 
666c65b1445SDouglas Gilbert 	return num;
667c65b1445SDouglas Gilbert }
668c65b1445SDouglas Gilbert 
669c65b1445SDouglas Gilbert 
670c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
671c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
672c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
673c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
674c65b1445SDouglas Gilbert '1','2','3','4',
675c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
676c65b1445SDouglas Gilbert 0xec,0,0,0,
677c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
678c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
679c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
680c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
681c65b1445SDouglas Gilbert 0x53,0x41,
682c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
683c65b1445SDouglas Gilbert 0x20,0x20,
684c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
685c65b1445SDouglas Gilbert 0x10,0x80,
686c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
687c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
688c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
689c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
690c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
691c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
692c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
693c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
694c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
695c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
696c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
697c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
698c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
699c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
700c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
701c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
702c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
703c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
704c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
705c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
706c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
707c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
708c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
709c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
710c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
711c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
712c65b1445SDouglas Gilbert };
713c65b1445SDouglas Gilbert 
714c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr)
715c65b1445SDouglas Gilbert {
716c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
717c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
718c65b1445SDouglas Gilbert }
719c65b1445SDouglas Gilbert 
720c65b1445SDouglas Gilbert 
7211e49f785SDouglas Gilbert /* Block limits VPD page (SBC-3) */
722c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
7231e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
7241e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7251e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7261e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
727c65b1445SDouglas Gilbert };
728c65b1445SDouglas Gilbert 
729c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr)
730c65b1445SDouglas Gilbert {
731ea61fca5SMartin K. Petersen 	unsigned int gran;
732ea61fca5SMartin K. Petersen 
733c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
734e308b3d1SMartin K. Petersen 
735e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
736ea61fca5SMartin K. Petersen 	gran = 1 << scsi_debug_physblk_exp;
737ea61fca5SMartin K. Petersen 	arr[2] = (gran >> 8) & 0xff;
738ea61fca5SMartin K. Petersen 	arr[3] = gran & 0xff;
739e308b3d1SMartin K. Petersen 
740e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
741c65b1445SDouglas Gilbert 	if (sdebug_store_sectors > 0x400) {
742c65b1445SDouglas Gilbert 		arr[4] = (sdebug_store_sectors >> 24) & 0xff;
743c65b1445SDouglas Gilbert 		arr[5] = (sdebug_store_sectors >> 16) & 0xff;
744c65b1445SDouglas Gilbert 		arr[6] = (sdebug_store_sectors >> 8) & 0xff;
745c65b1445SDouglas Gilbert 		arr[7] = sdebug_store_sectors & 0xff;
746c65b1445SDouglas Gilbert 	}
74744d92694SMartin K. Petersen 
748e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
749e308b3d1SMartin K. Petersen 	put_unaligned_be32(scsi_debug_opt_blks, &arr[8]);
750e308b3d1SMartin K. Petersen 
7515b94e232SMartin K. Petersen 	if (scsi_debug_lbpu) {
752e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
7536014759cSMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]);
754e308b3d1SMartin K. Petersen 
755e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
75644d92694SMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
75744d92694SMartin K. Petersen 	}
75844d92694SMartin K. Petersen 
759e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
76044d92694SMartin K. Petersen 	if (scsi_debug_unmap_alignment) {
76144d92694SMartin K. Petersen 		put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
76244d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
76344d92694SMartin K. Petersen 	}
76444d92694SMartin K. Petersen 
765e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
76644d92694SMartin K. Petersen 	put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
7676014759cSMartin K. Petersen 
7685b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
7695b94e232SMartin K. Petersen 	put_unaligned_be64(scsi_debug_write_same_length, &arr[32]);
7705b94e232SMartin K. Petersen 
7715b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
77244d92694SMartin K. Petersen 
773c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
7741da177e4SLinus Torvalds }
7751da177e4SLinus Torvalds 
7761e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
777eac6e8e4SMatthew Wilcox static int inquiry_evpd_b1(unsigned char *arr)
778eac6e8e4SMatthew Wilcox {
779eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
780eac6e8e4SMatthew Wilcox 	arr[0] = 0;
7811e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
7821e49f785SDouglas Gilbert 	arr[2] = 0;
7831e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
784eac6e8e4SMatthew Wilcox 
785eac6e8e4SMatthew Wilcox 	return 0x3c;
786eac6e8e4SMatthew Wilcox }
7871da177e4SLinus Torvalds 
788be1dd78dSEric Sandeen /* Logical block provisioning VPD page (SBC-3) */
7896014759cSMartin K. Petersen static int inquiry_evpd_b2(unsigned char *arr)
7906014759cSMartin K. Petersen {
7913f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
7926014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
7936014759cSMartin K. Petersen 
7945b94e232SMartin K. Petersen 	if (scsi_debug_lbpu)
7956014759cSMartin K. Petersen 		arr[1] = 1 << 7;
7966014759cSMartin K. Petersen 
7975b94e232SMartin K. Petersen 	if (scsi_debug_lbpws)
7986014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
7996014759cSMartin K. Petersen 
8005b94e232SMartin K. Petersen 	if (scsi_debug_lbpws10)
8015b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
8025b94e232SMartin K. Petersen 
803be1dd78dSEric Sandeen 	if (scsi_debug_lbprz)
804be1dd78dSEric Sandeen 		arr[1] |= 1 << 2;
805be1dd78dSEric Sandeen 
8063f0bc3b3SMartin K. Petersen 	return 0x4;
8076014759cSMartin K. Petersen }
8086014759cSMartin K. Petersen 
8091da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
810c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
8111da177e4SLinus Torvalds 
8121da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd * scp, int target,
8131da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
8141da177e4SLinus Torvalds {
8151da177e4SLinus Torvalds 	unsigned char pq_pdt;
8165a09e398SHannes Reinecke 	unsigned char * arr;
8171da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
8185a09e398SHannes Reinecke 	int alloc_len, n, ret;
8191da177e4SLinus Torvalds 
8201da177e4SLinus Torvalds 	alloc_len = (cmd[3] << 8) + cmd[4];
8216f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
8226f3cbf55SDouglas Gilbert 	if (! arr)
8236f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
824c65b1445SDouglas Gilbert 	if (devip->wlun)
825c65b1445SDouglas Gilbert 		pq_pdt = 0x1e;	/* present, wlun */
826c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (0 == devip->lun))
827c65b1445SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, no device type */
828c65b1445SDouglas Gilbert 	else
8291da177e4SLinus Torvalds 		pq_pdt = (scsi_debug_ptype & 0x1f);
8301da177e4SLinus Torvalds 	arr[0] = pq_pdt;
8311da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
8321da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
8331da177e4SLinus Torvalds 			       	0);
8345a09e398SHannes Reinecke 		kfree(arr);
8351da177e4SLinus Torvalds 		return check_condition_result;
8361da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
8375a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
838c65b1445SDouglas Gilbert 		char lu_id_str[6];
839c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
8401da177e4SLinus Torvalds 
8415a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
8425a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
84323183910SDouglas Gilbert 		if (0 == scsi_debug_vpd_use_hostno)
84423183910SDouglas Gilbert 			host_no = 0;
845c65b1445SDouglas Gilbert 		lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
846c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
847c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
848c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
849c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
8501da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
851c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
852c65b1445SDouglas Gilbert 			n = 4;
853c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
854c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
855c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
856c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
857c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
858c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
859c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
860c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
861c65b1445SDouglas Gilbert 			arr[n++] = 0x89;  /* ATA information */
862c65b1445SDouglas Gilbert 			arr[n++] = 0xb0;  /* Block limits (SBC) */
863eac6e8e4SMatthew Wilcox 			arr[n++] = 0xb1;  /* Block characteristics (SBC) */
8645b94e232SMartin K. Petersen 			if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
8655b94e232SMartin K. Petersen 				arr[n++] = 0xb2;
866c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
8671da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
868c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
8691da177e4SLinus Torvalds 			arr[3] = len;
870c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
8711da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
872c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
8735a09e398SHannes Reinecke 			arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
8745a09e398SHannes Reinecke 						 target_dev_id, lu_id_num,
8755a09e398SHannes Reinecke 						 lu_id_str, len);
876c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
877c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
878c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_84(&arr[4]);
879c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
880c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
881c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_85(&arr[4]);
882c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
883c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
884c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
885c6a44287SMartin K. Petersen 			if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
886c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
887c6a44287SMartin K. Petersen 			else if (scsi_debug_dif)
888c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
889c6a44287SMartin K. Petersen 			else
890c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
891c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
892c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
893c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
894c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
895c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
896c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
897c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
898c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
899c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
900c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
901c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
902c65b1445SDouglas Gilbert 		} else if (0x89 == cmd[2]) { /* ATA information */
903c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
904c65b1445SDouglas Gilbert 			n = inquiry_evpd_89(&arr[4]);
905c65b1445SDouglas Gilbert 			arr[2] = (n >> 8);
906c65b1445SDouglas Gilbert 			arr[3] = (n & 0xff);
907c65b1445SDouglas Gilbert 		} else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
908c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
909c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_b0(&arr[4]);
910eac6e8e4SMatthew Wilcox 		} else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
911eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
912eac6e8e4SMatthew Wilcox 			arr[3] = inquiry_evpd_b1(&arr[4]);
9135b94e232SMartin K. Petersen 		} else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
9146014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
9156014759cSMartin K. Petersen 			arr[3] = inquiry_evpd_b2(&arr[4]);
9161da177e4SLinus Torvalds 		} else {
9171da177e4SLinus Torvalds 			/* Illegal request, invalid field in cdb */
9181da177e4SLinus Torvalds 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
9191da177e4SLinus Torvalds 					INVALID_FIELD_IN_CDB, 0);
9205a09e398SHannes Reinecke 			kfree(arr);
9211da177e4SLinus Torvalds 			return check_condition_result;
9221da177e4SLinus Torvalds 		}
923c65b1445SDouglas Gilbert 		len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
9245a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
925c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
9265a09e398SHannes Reinecke 		kfree(arr);
9275a09e398SHannes Reinecke 		return ret;
9281da177e4SLinus Torvalds 	}
9291da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
930d986788bSMartin Pitt 	arr[1] = scsi_debug_removable ? 0x80 : 0;	/* Removable disk */
9311da177e4SLinus Torvalds 	arr[2] = scsi_debug_scsi_level;
9321da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
9331da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
934c6a44287SMartin K. Petersen 	arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
9355a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno)
9365a09e398SHannes Reinecke 		arr[5] = 0x10; /* claim: implicit TGPS */
937c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
9381da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
939c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
9401da177e4SLinus Torvalds 	memcpy(&arr[8], inq_vendor_id, 8);
9411da177e4SLinus Torvalds 	memcpy(&arr[16], inq_product_id, 16);
9421da177e4SLinus Torvalds 	memcpy(&arr[32], inq_product_rev, 4);
9431da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
944c65b1445SDouglas Gilbert 	arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
945c65b1445SDouglas Gilbert 	arr[60] = 0x3; arr[61] = 0x14;  /* SPC-3 ANSI */
946c65b1445SDouglas Gilbert 	n = 62;
9471da177e4SLinus Torvalds 	if (scsi_debug_ptype == 0) {
948c65b1445SDouglas Gilbert 		arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
9491da177e4SLinus Torvalds 	} else if (scsi_debug_ptype == 1) {
950c65b1445SDouglas Gilbert 		arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
9511da177e4SLinus Torvalds 	}
952c65b1445SDouglas Gilbert 	arr[n++] = 0xc; arr[n++] = 0xf;  /* SAS-1.1 rev 10 */
9535a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
9541da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
9555a09e398SHannes Reinecke 	kfree(arr);
9565a09e398SHannes Reinecke 	return ret;
9571da177e4SLinus Torvalds }
9581da177e4SLinus Torvalds 
9591da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp,
9601da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip)
9611da177e4SLinus Torvalds {
9621da177e4SLinus Torvalds 	unsigned char * sbuff;
9631da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
9641da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_SENSE_LEN];
965c65b1445SDouglas Gilbert 	int want_dsense;
9661da177e4SLinus Torvalds 	int len = 18;
9671da177e4SLinus Torvalds 
968c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
9691da177e4SLinus Torvalds 	if (devip->reset == 1)
970c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
971c65b1445SDouglas Gilbert 	want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
9721da177e4SLinus Torvalds 	sbuff = devip->sense_buff;
973c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
974c65b1445SDouglas Gilbert 		if (want_dsense) {
975c65b1445SDouglas Gilbert 			arr[0] = 0x72;
976c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
977c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
978c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
979c65b1445SDouglas Gilbert 		} else {
980c65b1445SDouglas Gilbert 			arr[0] = 0x70;
981c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
982c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
983c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
984c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
985c65b1445SDouglas Gilbert 		}
986c65b1445SDouglas Gilbert 	} else {
987c65b1445SDouglas Gilbert 		memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
9881da177e4SLinus Torvalds 		if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
9891da177e4SLinus Torvalds 			/* DESC bit set and sense_buff in fixed format */
990c65b1445SDouglas Gilbert 			memset(arr, 0, sizeof(arr));
9911da177e4SLinus Torvalds 			arr[0] = 0x72;
9921da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
9931da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
9941da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
9951da177e4SLinus Torvalds 			len = 8;
996c65b1445SDouglas Gilbert 		}
997c65b1445SDouglas Gilbert 	}
998c65b1445SDouglas Gilbert 	mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
9991da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
10001da177e4SLinus Torvalds }
10011da177e4SLinus Torvalds 
1002c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp,
1003c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
1004c65b1445SDouglas Gilbert {
1005c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1006c65b1445SDouglas Gilbert 	int power_cond, errsts, start;
1007c65b1445SDouglas Gilbert 
1008c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1009c65b1445SDouglas Gilbert 		return errsts;
1010c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1011c65b1445SDouglas Gilbert 	if (power_cond) {
1012c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1013c65b1445SDouglas Gilbert 			       	0);
1014c65b1445SDouglas Gilbert 		return check_condition_result;
1015c65b1445SDouglas Gilbert 	}
1016c65b1445SDouglas Gilbert 	start = cmd[4] & 1;
1017c65b1445SDouglas Gilbert 	if (start == devip->stopped)
1018c65b1445SDouglas Gilbert 		devip->stopped = !start;
1019c65b1445SDouglas Gilbert 	return 0;
1020c65b1445SDouglas Gilbert }
1021c65b1445SDouglas Gilbert 
102228898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
102328898873SFUJITA Tomonori {
102428898873SFUJITA Tomonori 	if (scsi_debug_virtual_gb > 0)
10255447ed6cSDouglas Gilbert 		return (sector_t)scsi_debug_virtual_gb *
10265447ed6cSDouglas Gilbert 			(1073741824 / scsi_debug_sector_size);
102728898873SFUJITA Tomonori 	else
102828898873SFUJITA Tomonori 		return sdebug_store_sectors;
102928898873SFUJITA Tomonori }
103028898873SFUJITA Tomonori 
10311da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
10321da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp,
10331da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
10341da177e4SLinus Torvalds {
10351da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1036c65b1445SDouglas Gilbert 	unsigned int capac;
10371da177e4SLinus Torvalds 	int errsts;
10381da177e4SLinus Torvalds 
1039c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
10401da177e4SLinus Torvalds 		return errsts;
1041c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
104228898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
10431da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1044c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1045c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
10461da177e4SLinus Torvalds 		arr[0] = (capac >> 24);
10471da177e4SLinus Torvalds 		arr[1] = (capac >> 16) & 0xff;
10481da177e4SLinus Torvalds 		arr[2] = (capac >> 8) & 0xff;
10491da177e4SLinus Torvalds 		arr[3] = capac & 0xff;
1050c65b1445SDouglas Gilbert 	} else {
1051c65b1445SDouglas Gilbert 		arr[0] = 0xff;
1052c65b1445SDouglas Gilbert 		arr[1] = 0xff;
1053c65b1445SDouglas Gilbert 		arr[2] = 0xff;
1054c65b1445SDouglas Gilbert 		arr[3] = 0xff;
1055c65b1445SDouglas Gilbert 	}
1056597136abSMartin K. Petersen 	arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
1057597136abSMartin K. Petersen 	arr[7] = scsi_debug_sector_size & 0xff;
10581da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
10591da177e4SLinus Torvalds }
10601da177e4SLinus Torvalds 
1061c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1062c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp,
1063c65b1445SDouglas Gilbert 			  struct sdebug_dev_info * devip)
1064c65b1445SDouglas Gilbert {
1065c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1066c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1067c65b1445SDouglas Gilbert 	unsigned long long capac;
1068c65b1445SDouglas Gilbert 	int errsts, k, alloc_len;
1069c65b1445SDouglas Gilbert 
1070c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1071c65b1445SDouglas Gilbert 		return errsts;
1072c65b1445SDouglas Gilbert 	alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1073c65b1445SDouglas Gilbert 		     + cmd[13]);
1074c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
107528898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1076c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1077c65b1445SDouglas Gilbert 	capac = sdebug_capacity - 1;
1078c65b1445SDouglas Gilbert 	for (k = 0; k < 8; ++k, capac >>= 8)
1079c65b1445SDouglas Gilbert 		arr[7 - k] = capac & 0xff;
1080597136abSMartin K. Petersen 	arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
1081597136abSMartin K. Petersen 	arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
1082597136abSMartin K. Petersen 	arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
1083597136abSMartin K. Petersen 	arr[11] = scsi_debug_sector_size & 0xff;
1084ea61fca5SMartin K. Petersen 	arr[13] = scsi_debug_physblk_exp & 0xf;
1085ea61fca5SMartin K. Petersen 	arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
108644d92694SMartin K. Petersen 
1087be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
10885b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1089be1dd78dSEric Sandeen 		if (scsi_debug_lbprz)
1090be1dd78dSEric Sandeen 			arr[14] |= 0x40; /* LBPRZ */
1091be1dd78dSEric Sandeen 	}
109244d92694SMartin K. Petersen 
1093ea61fca5SMartin K. Petersen 	arr[15] = scsi_debug_lowest_aligned & 0xff;
1094c6a44287SMartin K. Petersen 
1095c6a44287SMartin K. Petersen 	if (scsi_debug_dif) {
1096c6a44287SMartin K. Petersen 		arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
1097c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1098c6a44287SMartin K. Petersen 	}
1099c6a44287SMartin K. Petersen 
1100c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1101c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1102c65b1445SDouglas Gilbert }
1103c65b1445SDouglas Gilbert 
11045a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
11055a09e398SHannes Reinecke 
11065a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp,
11075a09e398SHannes Reinecke 			      struct sdebug_dev_info * devip)
11085a09e398SHannes Reinecke {
11095a09e398SHannes Reinecke 	unsigned char *cmd = (unsigned char *)scp->cmnd;
11105a09e398SHannes Reinecke 	unsigned char * arr;
11115a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
11125a09e398SHannes Reinecke 	int n, ret, alen, rlen;
11135a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
11145a09e398SHannes Reinecke 
11155a09e398SHannes Reinecke 	alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
11165a09e398SHannes Reinecke 		+ cmd[9]);
11175a09e398SHannes Reinecke 
11186f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
11196f3cbf55SDouglas Gilbert 	if (! arr)
11206f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
11215a09e398SHannes Reinecke 	/*
11225a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
11235a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
11245a09e398SHannes Reinecke 	 * So we create two port groups with one port each
11255a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
11265a09e398SHannes Reinecke 	 */
11275a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
11285a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
11295a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
11305a09e398SHannes Reinecke 	    (devip->channel & 0x7f);
11315a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
11325a09e398SHannes Reinecke 	    (devip->channel & 0x7f) + 0x80;
11335a09e398SHannes Reinecke 
11345a09e398SHannes Reinecke 	/*
11355a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
11365a09e398SHannes Reinecke 	 */
11375a09e398SHannes Reinecke 	n = 4;
11385a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno) {
11395a09e398SHannes Reinecke 	    arr[n++] = host_no % 3; /* Asymm access state */
11405a09e398SHannes Reinecke 	    arr[n++] = 0x0F; /* claim: all states are supported */
11415a09e398SHannes Reinecke 	} else {
11425a09e398SHannes Reinecke 	    arr[n++] = 0x0; /* Active/Optimized path */
11435a09e398SHannes Reinecke 	    arr[n++] = 0x01; /* claim: only support active/optimized paths */
11445a09e398SHannes Reinecke 	}
11455a09e398SHannes Reinecke 	arr[n++] = (port_group_a >> 8) & 0xff;
11465a09e398SHannes Reinecke 	arr[n++] = port_group_a & 0xff;
11475a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11485a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
11495a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
11505a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
11515a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11525a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11535a09e398SHannes Reinecke 	arr[n++] = (port_a >> 8) & 0xff;
11545a09e398SHannes Reinecke 	arr[n++] = port_a & 0xff;
11555a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
11565a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
11575a09e398SHannes Reinecke 	arr[n++] = (port_group_b >> 8) & 0xff;
11585a09e398SHannes Reinecke 	arr[n++] = port_group_b & 0xff;
11595a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11605a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
11615a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
11625a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
11635a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11645a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
11655a09e398SHannes Reinecke 	arr[n++] = (port_b >> 8) & 0xff;
11665a09e398SHannes Reinecke 	arr[n++] = port_b & 0xff;
11675a09e398SHannes Reinecke 
11685a09e398SHannes Reinecke 	rlen = n - 4;
11695a09e398SHannes Reinecke 	arr[0] = (rlen >> 24) & 0xff;
11705a09e398SHannes Reinecke 	arr[1] = (rlen >> 16) & 0xff;
11715a09e398SHannes Reinecke 	arr[2] = (rlen >> 8) & 0xff;
11725a09e398SHannes Reinecke 	arr[3] = rlen & 0xff;
11735a09e398SHannes Reinecke 
11745a09e398SHannes Reinecke 	/*
11755a09e398SHannes Reinecke 	 * Return the smallest value of either
11765a09e398SHannes Reinecke 	 * - The allocated length
11775a09e398SHannes Reinecke 	 * - The constructed command length
11785a09e398SHannes Reinecke 	 * - The maximum array size
11795a09e398SHannes Reinecke 	 */
11805a09e398SHannes Reinecke 	rlen = min(alen,n);
11815a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
11825a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
11835a09e398SHannes Reinecke 	kfree(arr);
11845a09e398SHannes Reinecke 	return ret;
11855a09e398SHannes Reinecke }
11865a09e398SHannes Reinecke 
11871da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
11881da177e4SLinus Torvalds 
11891da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
11901da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
11911da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
11921da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
11931da177e4SLinus Torvalds 
11941da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
11951da177e4SLinus Torvalds 	if (1 == pcontrol)
11961da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
11971da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
11981da177e4SLinus Torvalds }
11991da177e4SLinus Torvalds 
12001da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
12011da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
12021da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
12031da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
12041da177e4SLinus Torvalds 
12051da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
12061da177e4SLinus Torvalds 	if (1 == pcontrol)
12071da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
12081da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
12091da177e4SLinus Torvalds }
12101da177e4SLinus Torvalds 
12111da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target)
12121da177e4SLinus Torvalds {       /* Format device page for mode_sense */
12131da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
12141da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
12151da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
12161da177e4SLinus Torvalds 
12171da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
12181da177e4SLinus Torvalds 	p[10] = (sdebug_sectors_per >> 8) & 0xff;
12191da177e4SLinus Torvalds 	p[11] = sdebug_sectors_per & 0xff;
1220597136abSMartin K. Petersen 	p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1221597136abSMartin K. Petersen 	p[13] = scsi_debug_sector_size & 0xff;
1222d986788bSMartin Pitt 	if (scsi_debug_removable)
12231da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
12241da177e4SLinus Torvalds 	if (1 == pcontrol)
12251da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
12261da177e4SLinus Torvalds 	return sizeof(format_pg);
12271da177e4SLinus Torvalds }
12281da177e4SLinus Torvalds 
12291da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
12301da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
12311da177e4SLinus Torvalds 	unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
12321da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
12331da177e4SLinus Torvalds 
12341da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
12351da177e4SLinus Torvalds 	if (1 == pcontrol)
12361da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(caching_pg) - 2);
12371da177e4SLinus Torvalds 	return sizeof(caching_pg);
12381da177e4SLinus Torvalds }
12391da177e4SLinus Torvalds 
12401da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
12411da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
1242c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1243c65b1445SDouglas Gilbert 				        0, 0, 0, 0};
1244c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
12451da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
12461da177e4SLinus Torvalds 
12471da177e4SLinus Torvalds 	if (scsi_debug_dsense)
12481da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
1249c65b1445SDouglas Gilbert 	else
1250c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
1251c6a44287SMartin K. Petersen 
1252c6a44287SMartin K. Petersen 	if (scsi_debug_ato)
1253c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1254c6a44287SMartin K. Petersen 
12551da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
12561da177e4SLinus Torvalds 	if (1 == pcontrol)
1257c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1258c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1259c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
12601da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
12611da177e4SLinus Torvalds }
12621da177e4SLinus Torvalds 
1263c65b1445SDouglas Gilbert 
12641da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
12651da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
1266c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
12671da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
1268c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1269c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
1270c65b1445SDouglas Gilbert 
12711da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
12721da177e4SLinus Torvalds 	if (1 == pcontrol)
1273c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1274c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1275c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
12761da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
12771da177e4SLinus Torvalds }
12781da177e4SLinus Torvalds 
1279c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1280c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
1281c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1282c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1283c65b1445SDouglas Gilbert 
1284c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1285c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1286c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1287c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
1288c65b1445SDouglas Gilbert }
1289c65b1445SDouglas Gilbert 
1290c65b1445SDouglas Gilbert 
1291c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1292c65b1445SDouglas Gilbert 			      int target_dev_id)
1293c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
1294c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1295c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1296c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1297c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1298c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
1299c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1300c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1301c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1302c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1303c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1304c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
1305c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1306c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1307c65b1445SDouglas Gilbert 		};
1308c65b1445SDouglas Gilbert 	int port_a, port_b;
1309c65b1445SDouglas Gilbert 
1310c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1311c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1312c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1313c65b1445SDouglas Gilbert 	p[20] = (port_a >> 24);
1314c65b1445SDouglas Gilbert 	p[21] = (port_a >> 16) & 0xff;
1315c65b1445SDouglas Gilbert 	p[22] = (port_a >> 8) & 0xff;
1316c65b1445SDouglas Gilbert 	p[23] = port_a & 0xff;
1317c65b1445SDouglas Gilbert 	p[48 + 20] = (port_b >> 24);
1318c65b1445SDouglas Gilbert 	p[48 + 21] = (port_b >> 16) & 0xff;
1319c65b1445SDouglas Gilbert 	p[48 + 22] = (port_b >> 8) & 0xff;
1320c65b1445SDouglas Gilbert 	p[48 + 23] = port_b & 0xff;
1321c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1322c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1323c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
1324c65b1445SDouglas Gilbert }
1325c65b1445SDouglas Gilbert 
1326c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1327c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
1328c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1329c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1330c65b1445SDouglas Gilbert 		};
1331c65b1445SDouglas Gilbert 
1332c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1333c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1334c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1335c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
1336c65b1445SDouglas Gilbert }
1337c65b1445SDouglas Gilbert 
13381da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
13391da177e4SLinus Torvalds 
13401da177e4SLinus Torvalds static int resp_mode_sense(struct scsi_cmnd * scp, int target,
13411da177e4SLinus Torvalds 			   struct sdebug_dev_info * devip)
13421da177e4SLinus Torvalds {
134323183910SDouglas Gilbert 	unsigned char dbd, llbaa;
134423183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
13451da177e4SLinus Torvalds 	unsigned char dev_spec;
134623183910SDouglas Gilbert 	int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
13471da177e4SLinus Torvalds 	unsigned char * ap;
13481da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
13491da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
13501da177e4SLinus Torvalds 
1351c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
13521da177e4SLinus Torvalds 		return errsts;
135323183910SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);
13541da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
13551da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
13561da177e4SLinus Torvalds 	subpcode = cmd[3];
13571da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
135823183910SDouglas Gilbert 	llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
135923183910SDouglas Gilbert 	if ((0 == scsi_debug_ptype) && (0 == dbd))
136023183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
136123183910SDouglas Gilbert 	else
136223183910SDouglas Gilbert 		bd_len = 0;
13631da177e4SLinus Torvalds 	alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
13641da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
13651da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
13661da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
13671da177e4SLinus Torvalds 			       	0);
13681da177e4SLinus Torvalds 		return check_condition_result;
13691da177e4SLinus Torvalds 	}
1370c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1371c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
137223183910SDouglas Gilbert 	/* set DPOFUA bit for disks */
137323183910SDouglas Gilbert 	if (0 == scsi_debug_ptype)
137423183910SDouglas Gilbert 		dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
137523183910SDouglas Gilbert 	else
137623183910SDouglas Gilbert 		dev_spec = 0x0;
13771da177e4SLinus Torvalds 	if (msense_6) {
13781da177e4SLinus Torvalds 		arr[2] = dev_spec;
137923183910SDouglas Gilbert 		arr[3] = bd_len;
13801da177e4SLinus Torvalds 		offset = 4;
13811da177e4SLinus Torvalds 	} else {
13821da177e4SLinus Torvalds 		arr[3] = dev_spec;
138323183910SDouglas Gilbert 		if (16 == bd_len)
138423183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
138523183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
13861da177e4SLinus Torvalds 		offset = 8;
13871da177e4SLinus Torvalds 	}
13881da177e4SLinus Torvalds 	ap = arr + offset;
138928898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
139028898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
139128898873SFUJITA Tomonori 
139223183910SDouglas Gilbert 	if (8 == bd_len) {
139323183910SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe) {
139423183910SDouglas Gilbert 			ap[0] = 0xff;
139523183910SDouglas Gilbert 			ap[1] = 0xff;
139623183910SDouglas Gilbert 			ap[2] = 0xff;
139723183910SDouglas Gilbert 			ap[3] = 0xff;
139823183910SDouglas Gilbert 		} else {
139923183910SDouglas Gilbert 			ap[0] = (sdebug_capacity >> 24) & 0xff;
140023183910SDouglas Gilbert 			ap[1] = (sdebug_capacity >> 16) & 0xff;
140123183910SDouglas Gilbert 			ap[2] = (sdebug_capacity >> 8) & 0xff;
140223183910SDouglas Gilbert 			ap[3] = sdebug_capacity & 0xff;
140323183910SDouglas Gilbert 		}
1404597136abSMartin K. Petersen 		ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1405597136abSMartin K. Petersen 		ap[7] = scsi_debug_sector_size & 0xff;
140623183910SDouglas Gilbert 		offset += bd_len;
140723183910SDouglas Gilbert 		ap = arr + offset;
140823183910SDouglas Gilbert 	} else if (16 == bd_len) {
140923183910SDouglas Gilbert 		unsigned long long capac = sdebug_capacity;
141023183910SDouglas Gilbert 
141123183910SDouglas Gilbert         	for (k = 0; k < 8; ++k, capac >>= 8)
141223183910SDouglas Gilbert                 	ap[7 - k] = capac & 0xff;
1413597136abSMartin K. Petersen 		ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1414597136abSMartin K. Petersen 		ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1415597136abSMartin K. Petersen 		ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1416597136abSMartin K. Petersen 		ap[15] = scsi_debug_sector_size & 0xff;
141723183910SDouglas Gilbert 		offset += bd_len;
141823183910SDouglas Gilbert 		ap = arr + offset;
141923183910SDouglas Gilbert 	}
14201da177e4SLinus Torvalds 
1421c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1422c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
14231da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
14241da177e4SLinus Torvalds 			       	0);
14251da177e4SLinus Torvalds 		return check_condition_result;
14261da177e4SLinus Torvalds 	}
14271da177e4SLinus Torvalds 	switch (pcode) {
14281da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
14291da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
14301da177e4SLinus Torvalds 		offset += len;
14311da177e4SLinus Torvalds 		break;
14321da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
14331da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
14341da177e4SLinus Torvalds 		offset += len;
14351da177e4SLinus Torvalds 		break;
14361da177e4SLinus Torvalds         case 0x3:       /* Format device page, direct access */
14371da177e4SLinus Torvalds                 len = resp_format_pg(ap, pcontrol, target);
14381da177e4SLinus Torvalds                 offset += len;
14391da177e4SLinus Torvalds                 break;
14401da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
14411da177e4SLinus Torvalds 		len = resp_caching_pg(ap, pcontrol, target);
14421da177e4SLinus Torvalds 		offset += len;
14431da177e4SLinus Torvalds 		break;
14441da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
14451da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
14461da177e4SLinus Torvalds 		offset += len;
14471da177e4SLinus Torvalds 		break;
1448c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
1449c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
1450c65b1445SDouglas Gilbert 		        mk_sense_buffer(devip, ILLEGAL_REQUEST,
1451c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1452c65b1445SDouglas Gilbert 			return check_condition_result;
1453c65b1445SDouglas Gilbert 	        }
1454c65b1445SDouglas Gilbert 		len = 0;
1455c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
1456c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1457c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
1458c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1459c65b1445SDouglas Gilbert 						  target_dev_id);
1460c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
1461c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
1462c65b1445SDouglas Gilbert 		offset += len;
1463c65b1445SDouglas Gilbert 		break;
14641da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
14651da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
14661da177e4SLinus Torvalds 		offset += len;
14671da177e4SLinus Torvalds 		break;
14681da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
1469c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
14701da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
14711da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
14721da177e4SLinus Torvalds 			len += resp_format_pg(ap + len, pcontrol, target);
14731da177e4SLinus Torvalds 			len += resp_caching_pg(ap + len, pcontrol, target);
14741da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1475c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1476c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
1477c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1478c65b1445SDouglas Gilbert 						  target, target_dev_id);
1479c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
1480c65b1445SDouglas Gilbert 			}
14811da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
1482c65b1445SDouglas Gilbert 		} else {
1483c65b1445SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
1484c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1485c65b1445SDouglas Gilbert 			return check_condition_result;
1486c65b1445SDouglas Gilbert                 }
14871da177e4SLinus Torvalds 		offset += len;
14881da177e4SLinus Torvalds 		break;
14891da177e4SLinus Torvalds 	default:
14901da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
14911da177e4SLinus Torvalds 			       	0);
14921da177e4SLinus Torvalds 		return check_condition_result;
14931da177e4SLinus Torvalds 	}
14941da177e4SLinus Torvalds 	if (msense_6)
14951da177e4SLinus Torvalds 		arr[0] = offset - 1;
14961da177e4SLinus Torvalds 	else {
14971da177e4SLinus Torvalds 		arr[0] = ((offset - 2) >> 8) & 0xff;
14981da177e4SLinus Torvalds 		arr[1] = (offset - 2) & 0xff;
14991da177e4SLinus Torvalds 	}
15001da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
15011da177e4SLinus Torvalds }
15021da177e4SLinus Torvalds 
1503c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
1504c65b1445SDouglas Gilbert 
1505c65b1445SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1506c65b1445SDouglas Gilbert 			    struct sdebug_dev_info * devip)
1507c65b1445SDouglas Gilbert {
1508c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1509c65b1445SDouglas Gilbert 	int param_len, res, errsts, mpage;
1510c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1511c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1512c65b1445SDouglas Gilbert 
1513c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1514c65b1445SDouglas Gilbert 		return errsts;
1515c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1516c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
1517c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
1518c65b1445SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1519c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1520c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1521c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
1522c65b1445SDouglas Gilbert 		return check_condition_result;
1523c65b1445SDouglas Gilbert 	}
1524c65b1445SDouglas Gilbert         res = fetch_to_dev_buffer(scp, arr, param_len);
1525c65b1445SDouglas Gilbert         if (-1 == res)
1526c65b1445SDouglas Gilbert                 return (DID_ERROR << 16);
1527c65b1445SDouglas Gilbert         else if ((res < param_len) &&
1528c65b1445SDouglas Gilbert                  (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1529c65b1445SDouglas Gilbert                 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1530c65b1445SDouglas Gilbert                        " IO sent=%d bytes\n", param_len, res);
1531c65b1445SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1532c65b1445SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
153323183910SDouglas Gilbert 	if (md_len > 2) {
1534c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1535c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_PARAM_LIST, 0);
1536c65b1445SDouglas Gilbert 		return check_condition_result;
1537c65b1445SDouglas Gilbert 	}
1538c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
1539c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
1540c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
1541c65b1445SDouglas Gilbert 	if (ps) {
1542c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1543c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_PARAM_LIST, 0);
1544c65b1445SDouglas Gilbert 		return check_condition_result;
1545c65b1445SDouglas Gilbert 	}
1546c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
1547c65b1445SDouglas Gilbert 	pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1548c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
1549c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
1550c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1551c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
1552c65b1445SDouglas Gilbert 		return check_condition_result;
1553c65b1445SDouglas Gilbert 	}
1554c65b1445SDouglas Gilbert 	switch (mpage) {
1555c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
1556c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
1557c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
1558c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
1559c65b1445SDouglas Gilbert 			scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1560c65b1445SDouglas Gilbert 			return 0;
1561c65b1445SDouglas Gilbert 		}
1562c65b1445SDouglas Gilbert 		break;
1563c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
1564c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
1565c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
1566c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
1567c65b1445SDouglas Gilbert 			return 0;
1568c65b1445SDouglas Gilbert 		}
1569c65b1445SDouglas Gilbert 		break;
1570c65b1445SDouglas Gilbert 	default:
1571c65b1445SDouglas Gilbert 		break;
1572c65b1445SDouglas Gilbert 	}
1573c65b1445SDouglas Gilbert 	mk_sense_buffer(devip, ILLEGAL_REQUEST,
1574c65b1445SDouglas Gilbert 			INVALID_FIELD_IN_PARAM_LIST, 0);
1575c65b1445SDouglas Gilbert 	return check_condition_result;
1576c65b1445SDouglas Gilbert }
1577c65b1445SDouglas Gilbert 
1578c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr)
1579c65b1445SDouglas Gilbert {
1580c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1581c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
1582c65b1445SDouglas Gilbert 		};
1583c65b1445SDouglas Gilbert 
1584c65b1445SDouglas Gilbert         memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1585c65b1445SDouglas Gilbert         return sizeof(temp_l_pg);
1586c65b1445SDouglas Gilbert }
1587c65b1445SDouglas Gilbert 
1588c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr)
1589c65b1445SDouglas Gilbert {
1590c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1591c65b1445SDouglas Gilbert 		};
1592c65b1445SDouglas Gilbert 
1593c65b1445SDouglas Gilbert         memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1594c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
1595c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
1596c65b1445SDouglas Gilbert 		arr[5] = 0xff;
1597c65b1445SDouglas Gilbert 	}
1598c65b1445SDouglas Gilbert         return sizeof(ie_l_pg);
1599c65b1445SDouglas Gilbert }
1600c65b1445SDouglas Gilbert 
1601c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
1602c65b1445SDouglas Gilbert 
1603c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp,
1604c65b1445SDouglas Gilbert                           struct sdebug_dev_info * devip)
1605c65b1445SDouglas Gilbert {
160623183910SDouglas Gilbert 	int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
1607c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1608c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1609c65b1445SDouglas Gilbert 
1610c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1611c65b1445SDouglas Gilbert 		return errsts;
1612c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1613c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
1614c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
1615c65b1445SDouglas Gilbert 	if (ppc || sp) {
1616c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1617c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
1618c65b1445SDouglas Gilbert 		return check_condition_result;
1619c65b1445SDouglas Gilbert 	}
1620c65b1445SDouglas Gilbert 	pcontrol = (cmd[2] & 0xc0) >> 6;
1621c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
162223183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
1623c65b1445SDouglas Gilbert 	alloc_len = (cmd[7] << 8) + cmd[8];
1624c65b1445SDouglas Gilbert 	arr[0] = pcode;
162523183910SDouglas Gilbert 	if (0 == subpcode) {
1626c65b1445SDouglas Gilbert 		switch (pcode) {
1627c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
1628c65b1445SDouglas Gilbert 			n = 4;
1629c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
1630c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
1631c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
1632c65b1445SDouglas Gilbert 			arr[3] = n - 4;
1633c65b1445SDouglas Gilbert 			break;
1634c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
1635c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
1636c65b1445SDouglas Gilbert 			break;
1637c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
1638c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
1639c65b1445SDouglas Gilbert 			break;
1640c65b1445SDouglas Gilbert 		default:
1641c65b1445SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
1642c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1643c65b1445SDouglas Gilbert 			return check_condition_result;
1644c65b1445SDouglas Gilbert 		}
164523183910SDouglas Gilbert 	} else if (0xff == subpcode) {
164623183910SDouglas Gilbert 		arr[0] |= 0x40;
164723183910SDouglas Gilbert 		arr[1] = subpcode;
164823183910SDouglas Gilbert 		switch (pcode) {
164923183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
165023183910SDouglas Gilbert 			n = 4;
165123183910SDouglas Gilbert 			arr[n++] = 0x0;
165223183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
165323183910SDouglas Gilbert 			arr[n++] = 0x0;
165423183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
165523183910SDouglas Gilbert 			arr[n++] = 0xd;
165623183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
165723183910SDouglas Gilbert 			arr[n++] = 0x2f;
165823183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
165923183910SDouglas Gilbert 			arr[3] = n - 4;
166023183910SDouglas Gilbert 			break;
166123183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
166223183910SDouglas Gilbert 			n = 4;
166323183910SDouglas Gilbert 			arr[n++] = 0xd;
166423183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
166523183910SDouglas Gilbert 			arr[3] = n - 4;
166623183910SDouglas Gilbert 			break;
166723183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
166823183910SDouglas Gilbert 			n = 4;
166923183910SDouglas Gilbert 			arr[n++] = 0x2f;
167023183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
167123183910SDouglas Gilbert 			arr[3] = n - 4;
167223183910SDouglas Gilbert 			break;
167323183910SDouglas Gilbert 		default:
167423183910SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
167523183910SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
167623183910SDouglas Gilbert 			return check_condition_result;
167723183910SDouglas Gilbert 		}
167823183910SDouglas Gilbert 	} else {
167923183910SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
168023183910SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
168123183910SDouglas Gilbert 		return check_condition_result;
168223183910SDouglas Gilbert 	}
1683c65b1445SDouglas Gilbert 	len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1684c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1685c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
1686c65b1445SDouglas Gilbert }
1687c65b1445SDouglas Gilbert 
168819789100SFUJITA Tomonori static int check_device_access_params(struct sdebug_dev_info *devi,
168919789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
16901da177e4SLinus Torvalds {
1691c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
169219789100SFUJITA Tomonori 		mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
16931da177e4SLinus Torvalds 		return check_condition_result;
16941da177e4SLinus Torvalds 	}
1695c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
1696c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
169719789100SFUJITA Tomonori 		mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
1698c65b1445SDouglas Gilbert 		return check_condition_result;
1699c65b1445SDouglas Gilbert 	}
170019789100SFUJITA Tomonori 	return 0;
170119789100SFUJITA Tomonori }
170219789100SFUJITA Tomonori 
1703a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
170419789100SFUJITA Tomonori static int do_device_access(struct scsi_cmnd *scmd,
170519789100SFUJITA Tomonori 			    struct sdebug_dev_info *devi,
170619789100SFUJITA Tomonori 			    unsigned long long lba, unsigned int num, int write)
170719789100SFUJITA Tomonori {
170819789100SFUJITA Tomonori 	int ret;
1709a361cc00SDarrick J. Wong 	unsigned long long block, rest = 0;
1710a4517511SAkinobu Mita 	struct scsi_data_buffer *sdb;
1711a4517511SAkinobu Mita 	enum dma_data_direction dir;
1712a4517511SAkinobu Mita 	size_t (*func)(struct scatterlist *, unsigned int, void *, size_t,
1713a4517511SAkinobu Mita 		       off_t);
171419789100SFUJITA Tomonori 
1715a4517511SAkinobu Mita 	if (write) {
1716a4517511SAkinobu Mita 		sdb = scsi_out(scmd);
1717a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
1718a4517511SAkinobu Mita 		func = sg_pcopy_to_buffer;
1719a4517511SAkinobu Mita 	} else {
1720a4517511SAkinobu Mita 		sdb = scsi_in(scmd);
1721a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
1722a4517511SAkinobu Mita 		func = sg_pcopy_from_buffer;
1723a4517511SAkinobu Mita 	}
1724a4517511SAkinobu Mita 
1725a4517511SAkinobu Mita 	if (!sdb->length)
1726a4517511SAkinobu Mita 		return 0;
1727a4517511SAkinobu Mita 	if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
1728a4517511SAkinobu Mita 		return -1;
172919789100SFUJITA Tomonori 
173019789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
173119789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
173219789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
173319789100SFUJITA Tomonori 
1734a4517511SAkinobu Mita 	ret = func(sdb->table.sgl, sdb->table.nents,
1735a4517511SAkinobu Mita 		   fake_storep + (block * scsi_debug_sector_size),
1736a4517511SAkinobu Mita 		   (num - rest) * scsi_debug_sector_size, 0);
1737a4517511SAkinobu Mita 	if (ret != (num - rest) * scsi_debug_sector_size)
1738a4517511SAkinobu Mita 		return ret;
1739a4517511SAkinobu Mita 
1740a4517511SAkinobu Mita 	if (rest) {
1741a4517511SAkinobu Mita 		ret += func(sdb->table.sgl, sdb->table.nents,
1742a4517511SAkinobu Mita 			    fake_storep, rest * scsi_debug_sector_size,
1743597136abSMartin K. Petersen 			    (num - rest) * scsi_debug_sector_size);
1744a4517511SAkinobu Mita 	}
174519789100SFUJITA Tomonori 
174619789100SFUJITA Tomonori 	return ret;
174719789100SFUJITA Tomonori }
174819789100SFUJITA Tomonori 
174951d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
1750beb40ea4SAkinobu Mita {
175151d648afSAkinobu Mita 	__be16 csum;
1752beb40ea4SAkinobu Mita 
175351d648afSAkinobu Mita 	if (scsi_debug_guard)
175451d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
175551d648afSAkinobu Mita 	else
1756beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
175751d648afSAkinobu Mita 
1758beb40ea4SAkinobu Mita 	return csum;
1759beb40ea4SAkinobu Mita }
1760beb40ea4SAkinobu Mita 
1761beb40ea4SAkinobu Mita static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
1762beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
1763beb40ea4SAkinobu Mita {
176451d648afSAkinobu Mita 	__be16 csum = dif_compute_csum(data, scsi_debug_sector_size);
1765beb40ea4SAkinobu Mita 
1766beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
1767beb40ea4SAkinobu Mita 		pr_err("%s: GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
1768beb40ea4SAkinobu Mita 			__func__,
1769beb40ea4SAkinobu Mita 			(unsigned long)sector,
1770beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
1771beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
1772beb40ea4SAkinobu Mita 		return 0x01;
1773beb40ea4SAkinobu Mita 	}
1774beb40ea4SAkinobu Mita 	if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
1775beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
1776beb40ea4SAkinobu Mita 		pr_err("%s: REF check failed on sector %lu\n",
1777beb40ea4SAkinobu Mita 			__func__, (unsigned long)sector);
1778beb40ea4SAkinobu Mita 		return 0x03;
1779beb40ea4SAkinobu Mita 	}
1780beb40ea4SAkinobu Mita 	if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1781beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
1782beb40ea4SAkinobu Mita 		pr_err("%s: REF check failed on sector %lu\n",
1783beb40ea4SAkinobu Mita 			__func__, (unsigned long)sector);
1784beb40ea4SAkinobu Mita 		return 0x03;
1785beb40ea4SAkinobu Mita 	}
1786beb40ea4SAkinobu Mita 	return 0;
1787beb40ea4SAkinobu Mita }
1788beb40ea4SAkinobu Mita 
1789bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
179065f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
1791c6a44287SMartin K. Petersen {
1792c6a44287SMartin K. Petersen 	unsigned int i, resid;
1793c6a44287SMartin K. Petersen 	struct scatterlist *psgl;
1794c6a44287SMartin K. Petersen 	void *paddr;
179514faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
1796c6a44287SMartin K. Petersen 
1797e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
1798e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
1799c6a44287SMartin K. Petersen 
1800c6a44287SMartin K. Petersen 	scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
1801c6a44287SMartin K. Petersen 		int len = min(psgl->length, resid);
180214faa944SAkinobu Mita 		void *start = dif_store(sector);
180314faa944SAkinobu Mita 		int rest = 0;
180414faa944SAkinobu Mita 
180514faa944SAkinobu Mita 		if (dif_store_end < start + len)
180614faa944SAkinobu Mita 			rest = start + len - dif_store_end;
1807c6a44287SMartin K. Petersen 
180877dfce07SCong Wang 		paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
180914faa944SAkinobu Mita 
181065f72f2aSAkinobu Mita 		if (read)
181165f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
181265f72f2aSAkinobu Mita 		else
181365f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
181465f72f2aSAkinobu Mita 
181565f72f2aSAkinobu Mita 		if (rest) {
181665f72f2aSAkinobu Mita 			if (read)
181714faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
181865f72f2aSAkinobu Mita 			else
181965f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
182065f72f2aSAkinobu Mita 		}
1821c6a44287SMartin K. Petersen 
1822e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
1823c6a44287SMartin K. Petersen 		resid -= len;
182477dfce07SCong Wang 		kunmap_atomic(paddr);
1825c6a44287SMartin K. Petersen 	}
1826bb8c063cSAkinobu Mita }
1827c6a44287SMartin K. Petersen 
1828bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
1829bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
1830bb8c063cSAkinobu Mita {
1831bb8c063cSAkinobu Mita 	unsigned int i;
1832bb8c063cSAkinobu Mita 	struct sd_dif_tuple *sdt;
1833bb8c063cSAkinobu Mita 	sector_t sector;
1834bb8c063cSAkinobu Mita 
1835c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
1836bb8c063cSAkinobu Mita 		int ret;
1837bb8c063cSAkinobu Mita 
1838bb8c063cSAkinobu Mita 		sector = start_sec + i;
1839bb8c063cSAkinobu Mita 		sdt = dif_store(sector);
1840bb8c063cSAkinobu Mita 
184151d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
1842bb8c063cSAkinobu Mita 			continue;
1843bb8c063cSAkinobu Mita 
1844bb8c063cSAkinobu Mita 		ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
1845bb8c063cSAkinobu Mita 		if (ret) {
1846bb8c063cSAkinobu Mita 			dif_errors++;
1847bb8c063cSAkinobu Mita 			return ret;
1848bb8c063cSAkinobu Mita 		}
1849bb8c063cSAkinobu Mita 	}
1850bb8c063cSAkinobu Mita 
185165f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, true);
1852c6a44287SMartin K. Petersen 	dix_reads++;
1853c6a44287SMartin K. Petersen 
1854c6a44287SMartin K. Petersen 	return 0;
1855c6a44287SMartin K. Petersen }
1856c6a44287SMartin K. Petersen 
185719789100SFUJITA Tomonori static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
1858395cef03SMartin K. Petersen 		     unsigned int num, struct sdebug_dev_info *devip,
1859395cef03SMartin K. Petersen 		     u32 ei_lba)
186019789100SFUJITA Tomonori {
186119789100SFUJITA Tomonori 	unsigned long iflags;
186219789100SFUJITA Tomonori 	int ret;
186319789100SFUJITA Tomonori 
186419789100SFUJITA Tomonori 	ret = check_device_access_params(devip, lba, num);
186519789100SFUJITA Tomonori 	if (ret)
186619789100SFUJITA Tomonori 		return ret;
186719789100SFUJITA Tomonori 
18681da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
186932f7ef73SDouglas Gilbert 	    (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
1870c65b1445SDouglas Gilbert 	    ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1871c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
187232f7ef73SDouglas Gilbert 		mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
1873c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
1874c65b1445SDouglas Gilbert 		if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1875c65b1445SDouglas Gilbert 			devip->sense_buff[0] |= 0x80;	/* Valid bit */
187632f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
187732f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
1878c65b1445SDouglas Gilbert 			devip->sense_buff[3] = (ret >> 24) & 0xff;
1879c65b1445SDouglas Gilbert 			devip->sense_buff[4] = (ret >> 16) & 0xff;
1880c65b1445SDouglas Gilbert 			devip->sense_buff[5] = (ret >> 8) & 0xff;
1881c65b1445SDouglas Gilbert 			devip->sense_buff[6] = ret & 0xff;
1882c65b1445SDouglas Gilbert 		}
1883a87e3a67SDouglas Gilbert 	        scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
18841da177e4SLinus Torvalds 		return check_condition_result;
18851da177e4SLinus Torvalds 	}
1886c6a44287SMartin K. Petersen 
1887c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
1888c6a44287SMartin K. Petersen 	if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
1889395cef03SMartin K. Petersen 		int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
1890c6a44287SMartin K. Petersen 
1891c6a44287SMartin K. Petersen 		if (prot_ret) {
1892c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
1893c6a44287SMartin K. Petersen 			return illegal_condition_result;
1894c6a44287SMartin K. Petersen 		}
1895c6a44287SMartin K. Petersen 	}
1896c6a44287SMartin K. Petersen 
18971da177e4SLinus Torvalds 	read_lock_irqsave(&atomic_rw, iflags);
189819789100SFUJITA Tomonori 	ret = do_device_access(SCpnt, devip, lba, num, 0);
18991da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
1900a4517511SAkinobu Mita 	if (ret == -1)
1901a4517511SAkinobu Mita 		return DID_ERROR << 16;
1902a4517511SAkinobu Mita 
1903a4517511SAkinobu Mita 	scsi_in(SCpnt)->resid = scsi_bufflen(SCpnt) - ret;
1904a4517511SAkinobu Mita 
1905a4517511SAkinobu Mita 	return 0;
19061da177e4SLinus Torvalds }
19071da177e4SLinus Torvalds 
1908c6a44287SMartin K. Petersen void dump_sector(unsigned char *buf, int len)
1909c6a44287SMartin K. Petersen {
1910c6a44287SMartin K. Petersen 	int i, j;
1911c6a44287SMartin K. Petersen 
1912c6a44287SMartin K. Petersen 	printk(KERN_ERR ">>> Sector Dump <<<\n");
1913c6a44287SMartin K. Petersen 
1914c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
1915c6a44287SMartin K. Petersen 		printk(KERN_ERR "%04d: ", i);
1916c6a44287SMartin K. Petersen 
1917c6a44287SMartin K. Petersen 		for (j = 0 ; j < 16 ; j++) {
1918c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
1919c6a44287SMartin K. Petersen 			if (c >= 0x20 && c < 0x7e)
1920c6a44287SMartin K. Petersen 				printk(" %c ", buf[i+j]);
1921c6a44287SMartin K. Petersen 			else
1922c6a44287SMartin K. Petersen 				printk("%02x ", buf[i+j]);
1923c6a44287SMartin K. Petersen 		}
1924c6a44287SMartin K. Petersen 
1925c6a44287SMartin K. Petersen 		printk("\n");
1926c6a44287SMartin K. Petersen 	}
1927c6a44287SMartin K. Petersen }
1928c6a44287SMartin K. Petersen 
1929c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
1930395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
1931c6a44287SMartin K. Petersen {
1932c6a44287SMartin K. Petersen 	int i, j, ret;
1933c6a44287SMartin K. Petersen 	struct sd_dif_tuple *sdt;
193465f72f2aSAkinobu Mita 	struct scatterlist *dsgl;
1935c6a44287SMartin K. Petersen 	struct scatterlist *psgl = scsi_prot_sglist(SCpnt);
1936c6a44287SMartin K. Petersen 	void *daddr, *paddr;
193765f72f2aSAkinobu Mita 	sector_t sector = start_sec;
1938c6a44287SMartin K. Petersen 	int ppage_offset;
1939c6a44287SMartin K. Petersen 
1940c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
1941c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
1942c6a44287SMartin K. Petersen 
1943c6a44287SMartin K. Petersen 	ppage_offset = 0;
1944c6a44287SMartin K. Petersen 
1945c6a44287SMartin K. Petersen 	/* For each data page */
1946c6a44287SMartin K. Petersen 	scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
194777dfce07SCong Wang 		daddr = kmap_atomic(sg_page(dsgl)) + dsgl->offset;
1948fc3fc352SAkinobu Mita 		paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
1949c6a44287SMartin K. Petersen 
1950c6a44287SMartin K. Petersen 		/* For each sector-sized chunk in data page */
1951c6a44287SMartin K. Petersen 		for (j = 0; j < dsgl->length; j += scsi_debug_sector_size) {
1952c6a44287SMartin K. Petersen 
1953c6a44287SMartin K. Petersen 			/* If we're at the end of the current
1954c6a44287SMartin K. Petersen 			 * protection page advance to the next one
1955c6a44287SMartin K. Petersen 			 */
1956c6a44287SMartin K. Petersen 			if (ppage_offset >= psgl->length) {
195777dfce07SCong Wang 				kunmap_atomic(paddr);
1958c6a44287SMartin K. Petersen 				psgl = sg_next(psgl);
1959c6a44287SMartin K. Petersen 				BUG_ON(psgl == NULL);
196077dfce07SCong Wang 				paddr = kmap_atomic(sg_page(psgl))
1961c6a44287SMartin K. Petersen 					+ psgl->offset;
1962c6a44287SMartin K. Petersen 				ppage_offset = 0;
1963c6a44287SMartin K. Petersen 			}
1964c6a44287SMartin K. Petersen 
1965c6a44287SMartin K. Petersen 			sdt = paddr + ppage_offset;
1966c6a44287SMartin K. Petersen 
196765f72f2aSAkinobu Mita 			ret = dif_verify(sdt, daddr + j, sector, ei_lba);
1968beb40ea4SAkinobu Mita 			if (ret) {
1969518d9df8SAkinobu Mita 				dump_sector(daddr + j, scsi_debug_sector_size);
1970395cef03SMartin K. Petersen 				goto out;
1971395cef03SMartin K. Petersen 			}
1972395cef03SMartin K. Petersen 
1973c6a44287SMartin K. Petersen 			sector++;
1974395cef03SMartin K. Petersen 			ei_lba++;
1975c6a44287SMartin K. Petersen 			ppage_offset += sizeof(struct sd_dif_tuple);
1976c6a44287SMartin K. Petersen 		}
1977c6a44287SMartin K. Petersen 
1978fc3fc352SAkinobu Mita 		kunmap_atomic(paddr);
197977dfce07SCong Wang 		kunmap_atomic(daddr);
1980c6a44287SMartin K. Petersen 	}
1981c6a44287SMartin K. Petersen 
198265f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
1983c6a44287SMartin K. Petersen 	dix_writes++;
1984c6a44287SMartin K. Petersen 
1985c6a44287SMartin K. Petersen 	return 0;
1986c6a44287SMartin K. Petersen 
1987c6a44287SMartin K. Petersen out:
1988c6a44287SMartin K. Petersen 	dif_errors++;
198977dfce07SCong Wang 	kunmap_atomic(paddr);
1990fc3fc352SAkinobu Mita 	kunmap_atomic(daddr);
1991c6a44287SMartin K. Petersen 	return ret;
1992c6a44287SMartin K. Petersen }
1993c6a44287SMartin K. Petersen 
1994b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
1995b90ebc3dSAkinobu Mita {
1996b90ebc3dSAkinobu Mita 	if (scsi_debug_unmap_alignment) {
1997b90ebc3dSAkinobu Mita 		lba += scsi_debug_unmap_granularity -
1998b90ebc3dSAkinobu Mita 			scsi_debug_unmap_alignment;
1999b90ebc3dSAkinobu Mita 	}
2000b90ebc3dSAkinobu Mita 	do_div(lba, scsi_debug_unmap_granularity);
2001b90ebc3dSAkinobu Mita 
2002b90ebc3dSAkinobu Mita 	return lba;
2003b90ebc3dSAkinobu Mita }
2004b90ebc3dSAkinobu Mita 
2005b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
2006b90ebc3dSAkinobu Mita {
2007a027b5b9SAkinobu Mita 	sector_t lba = index * scsi_debug_unmap_granularity;
2008a027b5b9SAkinobu Mita 
2009a027b5b9SAkinobu Mita 	if (scsi_debug_unmap_alignment) {
2010a027b5b9SAkinobu Mita 		lba -= scsi_debug_unmap_granularity -
2011b90ebc3dSAkinobu Mita 			scsi_debug_unmap_alignment;
2012b90ebc3dSAkinobu Mita 	}
2013b90ebc3dSAkinobu Mita 
2014a027b5b9SAkinobu Mita 	return lba;
2015a027b5b9SAkinobu Mita }
2016a027b5b9SAkinobu Mita 
201744d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
201844d92694SMartin K. Petersen {
2019b90ebc3dSAkinobu Mita 	sector_t end;
2020b90ebc3dSAkinobu Mita 	unsigned int mapped;
2021b90ebc3dSAkinobu Mita 	unsigned long index;
2022b90ebc3dSAkinobu Mita 	unsigned long next;
202344d92694SMartin K. Petersen 
2024b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
2025b90ebc3dSAkinobu Mita 	mapped = test_bit(index, map_storep);
202644d92694SMartin K. Petersen 
202744d92694SMartin K. Petersen 	if (mapped)
2028b90ebc3dSAkinobu Mita 		next = find_next_zero_bit(map_storep, map_size, index);
202944d92694SMartin K. Petersen 	else
2030b90ebc3dSAkinobu Mita 		next = find_next_bit(map_storep, map_size, index);
203144d92694SMartin K. Petersen 
2032b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
203344d92694SMartin K. Petersen 	*num = end - lba;
203444d92694SMartin K. Petersen 
203544d92694SMartin K. Petersen 	return mapped;
203644d92694SMartin K. Petersen }
203744d92694SMartin K. Petersen 
203844d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
203944d92694SMartin K. Petersen {
204044d92694SMartin K. Petersen 	sector_t end = lba + len;
204144d92694SMartin K. Petersen 
204244d92694SMartin K. Petersen 	while (lba < end) {
2043b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
204444d92694SMartin K. Petersen 
2045b90ebc3dSAkinobu Mita 		if (index < map_size)
2046b90ebc3dSAkinobu Mita 			set_bit(index, map_storep);
204744d92694SMartin K. Petersen 
2048b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
204944d92694SMartin K. Petersen 	}
205044d92694SMartin K. Petersen }
205144d92694SMartin K. Petersen 
205244d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
205344d92694SMartin K. Petersen {
205444d92694SMartin K. Petersen 	sector_t end = lba + len;
205544d92694SMartin K. Petersen 
205644d92694SMartin K. Petersen 	while (lba < end) {
2057b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
205844d92694SMartin K. Petersen 
2059b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
2060b90ebc3dSAkinobu Mita 		    lba + scsi_debug_unmap_granularity <= end &&
2061b90ebc3dSAkinobu Mita 		    index < map_size) {
2062b90ebc3dSAkinobu Mita 			clear_bit(index, map_storep);
2063b90ebc3dSAkinobu Mita 			if (scsi_debug_lbprz) {
2064be1dd78dSEric Sandeen 				memset(fake_storep +
2065cc34a8e6SAkinobu Mita 				       lba * scsi_debug_sector_size, 0,
2066cc34a8e6SAkinobu Mita 				       scsi_debug_sector_size *
2067cc34a8e6SAkinobu Mita 				       scsi_debug_unmap_granularity);
2068be1dd78dSEric Sandeen 			}
2069e9926b43SAkinobu Mita 			if (dif_storep) {
2070e9926b43SAkinobu Mita 				memset(dif_storep + lba, 0xff,
2071e9926b43SAkinobu Mita 				       sizeof(*dif_storep) *
2072e9926b43SAkinobu Mita 				       scsi_debug_unmap_granularity);
2073e9926b43SAkinobu Mita 			}
2074b90ebc3dSAkinobu Mita 		}
2075b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
207644d92694SMartin K. Petersen 	}
207744d92694SMartin K. Petersen }
207844d92694SMartin K. Petersen 
2079c65b1445SDouglas Gilbert static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
2080395cef03SMartin K. Petersen 		      unsigned int num, struct sdebug_dev_info *devip,
2081395cef03SMartin K. Petersen 		      u32 ei_lba)
20821da177e4SLinus Torvalds {
20831da177e4SLinus Torvalds 	unsigned long iflags;
208419789100SFUJITA Tomonori 	int ret;
20851da177e4SLinus Torvalds 
208619789100SFUJITA Tomonori 	ret = check_device_access_params(devip, lba, num);
208719789100SFUJITA Tomonori 	if (ret)
208819789100SFUJITA Tomonori 		return ret;
20891da177e4SLinus Torvalds 
2090c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2091c6a44287SMartin K. Petersen 	if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
2092395cef03SMartin K. Petersen 		int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
2093c6a44287SMartin K. Petersen 
2094c6a44287SMartin K. Petersen 		if (prot_ret) {
2095c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
2096c6a44287SMartin K. Petersen 			return illegal_condition_result;
2097c6a44287SMartin K. Petersen 		}
2098c6a44287SMartin K. Petersen 	}
2099c6a44287SMartin K. Petersen 
21001da177e4SLinus Torvalds 	write_lock_irqsave(&atomic_rw, iflags);
210119789100SFUJITA Tomonori 	ret = do_device_access(SCpnt, devip, lba, num, 1);
21029ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
210344d92694SMartin K. Petersen 		map_region(lba, num);
21041da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
210519789100SFUJITA Tomonori 	if (-1 == ret)
21061da177e4SLinus Torvalds 		return (DID_ERROR << 16);
2107597136abSMartin K. Petersen 	else if ((ret < (num * scsi_debug_sector_size)) &&
21081da177e4SLinus Torvalds 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
2109c65b1445SDouglas Gilbert 		printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
2110597136abSMartin K. Petersen 		       " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
211144d92694SMartin K. Petersen 
21121da177e4SLinus Torvalds 	return 0;
21131da177e4SLinus Torvalds }
21141da177e4SLinus Torvalds 
211544d92694SMartin K. Petersen static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,
211644d92694SMartin K. Petersen 		      unsigned int num, struct sdebug_dev_info *devip,
211744d92694SMartin K. Petersen 			   u32 ei_lba, unsigned int unmap)
211844d92694SMartin K. Petersen {
211944d92694SMartin K. Petersen 	unsigned long iflags;
212044d92694SMartin K. Petersen 	unsigned long long i;
212144d92694SMartin K. Petersen 	int ret;
212244d92694SMartin K. Petersen 
212344d92694SMartin K. Petersen 	ret = check_device_access_params(devip, lba, num);
212444d92694SMartin K. Petersen 	if (ret)
212544d92694SMartin K. Petersen 		return ret;
212644d92694SMartin K. Petersen 
21275b94e232SMartin K. Petersen 	if (num > scsi_debug_write_same_length) {
21285b94e232SMartin K. Petersen 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
21295b94e232SMartin K. Petersen 				0);
21305b94e232SMartin K. Petersen 		return check_condition_result;
21315b94e232SMartin K. Petersen 	}
21325b94e232SMartin K. Petersen 
213344d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
213444d92694SMartin K. Petersen 
21359ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
213644d92694SMartin K. Petersen 		unmap_region(lba, num);
213744d92694SMartin K. Petersen 		goto out;
213844d92694SMartin K. Petersen 	}
213944d92694SMartin K. Petersen 
214044d92694SMartin K. Petersen 	/* Else fetch one logical block */
214144d92694SMartin K. Petersen 	ret = fetch_to_dev_buffer(scmd,
214244d92694SMartin K. Petersen 				  fake_storep + (lba * scsi_debug_sector_size),
214344d92694SMartin K. Petersen 				  scsi_debug_sector_size);
214444d92694SMartin K. Petersen 
214544d92694SMartin K. Petersen 	if (-1 == ret) {
214644d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
214744d92694SMartin K. Petersen 		return (DID_ERROR << 16);
214844d92694SMartin K. Petersen 	} else if ((ret < (num * scsi_debug_sector_size)) &&
214944d92694SMartin K. Petersen 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
215044d92694SMartin K. Petersen 		printk(KERN_INFO "scsi_debug: write same: cdb indicated=%u, "
215144d92694SMartin K. Petersen 		       " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
215244d92694SMartin K. Petersen 
215344d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
215444d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
215544d92694SMartin K. Petersen 		memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size),
215644d92694SMartin K. Petersen 		       fake_storep + (lba * scsi_debug_sector_size),
215744d92694SMartin K. Petersen 		       scsi_debug_sector_size);
215844d92694SMartin K. Petersen 
21599ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
216044d92694SMartin K. Petersen 		map_region(lba, num);
216144d92694SMartin K. Petersen out:
216244d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
216344d92694SMartin K. Petersen 
216444d92694SMartin K. Petersen 	return 0;
216544d92694SMartin K. Petersen }
216644d92694SMartin K. Petersen 
216744d92694SMartin K. Petersen struct unmap_block_desc {
216844d92694SMartin K. Petersen 	__be64	lba;
216944d92694SMartin K. Petersen 	__be32	blocks;
217044d92694SMartin K. Petersen 	__be32	__reserved;
217144d92694SMartin K. Petersen };
217244d92694SMartin K. Petersen 
217344d92694SMartin K. Petersen static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
217444d92694SMartin K. Petersen {
217544d92694SMartin K. Petersen 	unsigned char *buf;
217644d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
217744d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
217844d92694SMartin K. Petersen 	int ret;
217944d92694SMartin K. Petersen 
218044d92694SMartin K. Petersen 	ret = check_readiness(scmd, 1, devip);
218144d92694SMartin K. Petersen 	if (ret)
218244d92694SMartin K. Petersen 		return ret;
218344d92694SMartin K. Petersen 
218444d92694SMartin K. Petersen 	payload_len = get_unaligned_be16(&scmd->cmnd[7]);
218544d92694SMartin K. Petersen 	BUG_ON(scsi_bufflen(scmd) != payload_len);
218644d92694SMartin K. Petersen 
218744d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
218844d92694SMartin K. Petersen 
218944d92694SMartin K. Petersen 	buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC);
219044d92694SMartin K. Petersen 	if (!buf)
219144d92694SMartin K. Petersen 		return check_condition_result;
219244d92694SMartin K. Petersen 
219344d92694SMartin K. Petersen 	scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
219444d92694SMartin K. Petersen 
219544d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
219644d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
219744d92694SMartin K. Petersen 
219844d92694SMartin K. Petersen 	desc = (void *)&buf[8];
219944d92694SMartin K. Petersen 
220044d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
220144d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
220244d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
220344d92694SMartin K. Petersen 
220444d92694SMartin K. Petersen 		ret = check_device_access_params(devip, lba, num);
220544d92694SMartin K. Petersen 		if (ret)
220644d92694SMartin K. Petersen 			goto out;
220744d92694SMartin K. Petersen 
220844d92694SMartin K. Petersen 		unmap_region(lba, num);
220944d92694SMartin K. Petersen 	}
221044d92694SMartin K. Petersen 
221144d92694SMartin K. Petersen 	ret = 0;
221244d92694SMartin K. Petersen 
221344d92694SMartin K. Petersen out:
221444d92694SMartin K. Petersen 	kfree(buf);
221544d92694SMartin K. Petersen 
221644d92694SMartin K. Petersen 	return ret;
221744d92694SMartin K. Petersen }
221844d92694SMartin K. Petersen 
221944d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
222044d92694SMartin K. Petersen 
222144d92694SMartin K. Petersen static int resp_get_lba_status(struct scsi_cmnd * scmd,
222244d92694SMartin K. Petersen 			       struct sdebug_dev_info * devip)
222344d92694SMartin K. Petersen {
222444d92694SMartin K. Petersen 	unsigned long long lba;
222544d92694SMartin K. Petersen 	unsigned int alloc_len, mapped, num;
222644d92694SMartin K. Petersen 	unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN];
222744d92694SMartin K. Petersen 	int ret;
222844d92694SMartin K. Petersen 
222944d92694SMartin K. Petersen 	ret = check_readiness(scmd, 1, devip);
223044d92694SMartin K. Petersen 	if (ret)
223144d92694SMartin K. Petersen 		return ret;
223244d92694SMartin K. Petersen 
223344d92694SMartin K. Petersen 	lba = get_unaligned_be64(&scmd->cmnd[2]);
223444d92694SMartin K. Petersen 	alloc_len = get_unaligned_be32(&scmd->cmnd[10]);
223544d92694SMartin K. Petersen 
223644d92694SMartin K. Petersen 	if (alloc_len < 24)
223744d92694SMartin K. Petersen 		return 0;
223844d92694SMartin K. Petersen 
223944d92694SMartin K. Petersen 	ret = check_device_access_params(devip, lba, 1);
224044d92694SMartin K. Petersen 	if (ret)
224144d92694SMartin K. Petersen 		return ret;
224244d92694SMartin K. Petersen 
224344d92694SMartin K. Petersen 	mapped = map_state(lba, &num);
224444d92694SMartin K. Petersen 
224544d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
2246de13e965SDouglas Gilbert 	put_unaligned_be32(20, &arr[0]);	/* Parameter Data Length */
224744d92694SMartin K. Petersen 	put_unaligned_be64(lba, &arr[8]);	/* LBA */
224844d92694SMartin K. Petersen 	put_unaligned_be32(num, &arr[16]);	/* Number of blocks */
224944d92694SMartin K. Petersen 	arr[20] = !mapped;			/* mapped = 0, unmapped = 1 */
225044d92694SMartin K. Petersen 
225144d92694SMartin K. Petersen 	return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN);
225244d92694SMartin K. Petersen }
225344d92694SMartin K. Petersen 
2254c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256
22551da177e4SLinus Torvalds 
22561da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp,
22571da177e4SLinus Torvalds 			    struct sdebug_dev_info * devip)
22581da177e4SLinus Torvalds {
22591da177e4SLinus Torvalds 	unsigned int alloc_len;
2260c65b1445SDouglas Gilbert 	int lun_cnt, i, upper, num, n, wlun, lun;
22611da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
22621da177e4SLinus Torvalds 	int select_report = (int)cmd[2];
22631da177e4SLinus Torvalds 	struct scsi_lun *one_lun;
22641da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_RLUN_ARR_SZ];
2265c65b1445SDouglas Gilbert 	unsigned char * max_addr;
22661da177e4SLinus Torvalds 
22671da177e4SLinus Torvalds 	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
2268c65b1445SDouglas Gilbert 	if ((alloc_len < 4) || (select_report > 2)) {
22691da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
22701da177e4SLinus Torvalds 			       	0);
22711da177e4SLinus Torvalds 		return check_condition_result;
22721da177e4SLinus Torvalds 	}
22731da177e4SLinus Torvalds 	/* can produce response with up to 16k luns (lun 0 to lun 16383) */
22741da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
22751da177e4SLinus Torvalds 	lun_cnt = scsi_debug_max_luns;
2276c65b1445SDouglas Gilbert 	if (1 == select_report)
2277c65b1445SDouglas Gilbert 		lun_cnt = 0;
2278c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
2279c65b1445SDouglas Gilbert 		--lun_cnt;
2280c65b1445SDouglas Gilbert 	wlun = (select_report > 0) ? 1 : 0;
2281c65b1445SDouglas Gilbert 	num = lun_cnt + wlun;
2282c65b1445SDouglas Gilbert 	arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
2283c65b1445SDouglas Gilbert 	arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
2284c65b1445SDouglas Gilbert 	n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
2285c65b1445SDouglas Gilbert 			    sizeof(struct scsi_lun)), num);
2286c65b1445SDouglas Gilbert 	if (n < num) {
2287c65b1445SDouglas Gilbert 		wlun = 0;
2288c65b1445SDouglas Gilbert 		lun_cnt = n;
2289c65b1445SDouglas Gilbert 	}
22901da177e4SLinus Torvalds 	one_lun = (struct scsi_lun *) &arr[8];
2291c65b1445SDouglas Gilbert 	max_addr = arr + SDEBUG_RLUN_ARR_SZ;
2292c65b1445SDouglas Gilbert 	for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
2293c65b1445SDouglas Gilbert              ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
2294c65b1445SDouglas Gilbert 	     i++, lun++) {
2295c65b1445SDouglas Gilbert 		upper = (lun >> 8) & 0x3f;
22961da177e4SLinus Torvalds 		if (upper)
22971da177e4SLinus Torvalds 			one_lun[i].scsi_lun[0] =
22981da177e4SLinus Torvalds 			    (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
2299c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = lun & 0xff;
23001da177e4SLinus Torvalds 	}
2301c65b1445SDouglas Gilbert 	if (wlun) {
2302c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
2303c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
2304c65b1445SDouglas Gilbert 		i++;
2305c65b1445SDouglas Gilbert 	}
2306c65b1445SDouglas Gilbert 	alloc_len = (unsigned char *)(one_lun + i) - arr;
23071da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr,
23081da177e4SLinus Torvalds 				    min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
23091da177e4SLinus Torvalds }
23101da177e4SLinus Torvalds 
2311c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
2312c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
2313c639d14eSFUJITA Tomonori {
2314c639d14eSFUJITA Tomonori 	int i, j, ret = -1;
2315c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
2316c639d14eSFUJITA Tomonori 	unsigned int offset;
2317c639d14eSFUJITA Tomonori 	struct scatterlist *sg;
2318c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
2319c639d14eSFUJITA Tomonori 
2320c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
2321c639d14eSFUJITA Tomonori 	buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
2322c5af0db9SAkinobu Mita 	if (!buf) {
2323c5af0db9SAkinobu Mita 		mk_sense_buffer(devip, NOT_READY,
2324c5af0db9SAkinobu Mita 				LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
2325c5af0db9SAkinobu Mita 		return check_condition_result;
2326c5af0db9SAkinobu Mita 	}
2327c639d14eSFUJITA Tomonori 
232821a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
2329c639d14eSFUJITA Tomonori 
2330c639d14eSFUJITA Tomonori 	offset = 0;
2331c639d14eSFUJITA Tomonori 	for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
233277dfce07SCong Wang 		kaddr = (unsigned char *)kmap_atomic(sg_page(sg));
2333c639d14eSFUJITA Tomonori 		if (!kaddr)
2334c639d14eSFUJITA Tomonori 			goto out;
2335c639d14eSFUJITA Tomonori 
2336c639d14eSFUJITA Tomonori 		for (j = 0; j < sg->length; j++)
2337c639d14eSFUJITA Tomonori 			*(kaddr + sg->offset + j) ^= *(buf + offset + j);
2338c639d14eSFUJITA Tomonori 
2339c639d14eSFUJITA Tomonori 		offset += sg->length;
234077dfce07SCong Wang 		kunmap_atomic(kaddr);
2341c639d14eSFUJITA Tomonori 	}
2342c639d14eSFUJITA Tomonori 	ret = 0;
2343c639d14eSFUJITA Tomonori out:
2344c639d14eSFUJITA Tomonori 	kfree(buf);
2345c639d14eSFUJITA Tomonori 
2346c639d14eSFUJITA Tomonori 	return ret;
2347c639d14eSFUJITA Tomonori }
2348c639d14eSFUJITA Tomonori 
23491da177e4SLinus Torvalds /* When timer goes off this function is called. */
23501da177e4SLinus Torvalds static void timer_intr_handler(unsigned long indx)
23511da177e4SLinus Torvalds {
23521da177e4SLinus Torvalds 	struct sdebug_queued_cmd * sqcp;
23531da177e4SLinus Torvalds 	unsigned long iflags;
23541da177e4SLinus Torvalds 
235578d4e5a0SDouglas Gilbert 	if (indx >= scsi_debug_max_queue) {
23561da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
23571da177e4SLinus Torvalds 		       "large\n");
23581da177e4SLinus Torvalds 		return;
23591da177e4SLinus Torvalds 	}
23601da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
23611da177e4SLinus Torvalds 	sqcp = &queued_arr[(int)indx];
23621da177e4SLinus Torvalds 	if (! sqcp->in_use) {
23631da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
23641da177e4SLinus Torvalds 		       "interrupt\n");
23651da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
23661da177e4SLinus Torvalds 		return;
23671da177e4SLinus Torvalds 	}
23681da177e4SLinus Torvalds 	sqcp->in_use = 0;
23691da177e4SLinus Torvalds 	if (sqcp->done_funct) {
23701da177e4SLinus Torvalds 		sqcp->a_cmnd->result = sqcp->scsi_result;
23711da177e4SLinus Torvalds 		sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
23721da177e4SLinus Torvalds 	}
23731da177e4SLinus Torvalds 	sqcp->done_funct = NULL;
23741da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
23751da177e4SLinus Torvalds }
23761da177e4SLinus Torvalds 
23771da177e4SLinus Torvalds 
23788dea0d02SFUJITA Tomonori static struct sdebug_dev_info *
23798dea0d02SFUJITA Tomonori sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
23805cb2fc06SFUJITA Tomonori {
23815cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
23825cb2fc06SFUJITA Tomonori 
23835cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
23845cb2fc06SFUJITA Tomonori 	if (devip) {
23855cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
23865cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
23875cb2fc06SFUJITA Tomonori 	}
23885cb2fc06SFUJITA Tomonori 	return devip;
23895cb2fc06SFUJITA Tomonori }
23905cb2fc06SFUJITA Tomonori 
23911da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
23921da177e4SLinus Torvalds {
23931da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
23941da177e4SLinus Torvalds 	struct sdebug_dev_info * open_devip = NULL;
23951da177e4SLinus Torvalds 	struct sdebug_dev_info * devip =
23961da177e4SLinus Torvalds 			(struct sdebug_dev_info *)sdev->hostdata;
23971da177e4SLinus Torvalds 
23981da177e4SLinus Torvalds 	if (devip)
23991da177e4SLinus Torvalds 		return devip;
2400d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
24011da177e4SLinus Torvalds 	if (!sdbg_host) {
24021da177e4SLinus Torvalds                 printk(KERN_ERR "Host info NULL\n");
24031da177e4SLinus Torvalds 		return NULL;
24041da177e4SLinus Torvalds         }
24051da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
24061da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
24071da177e4SLinus Torvalds                     (devip->target == sdev->id) &&
24081da177e4SLinus Torvalds                     (devip->lun == sdev->lun))
24091da177e4SLinus Torvalds                         return devip;
24101da177e4SLinus Torvalds 		else {
24111da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
24121da177e4SLinus Torvalds 				open_devip = devip;
24131da177e4SLinus Torvalds 		}
24141da177e4SLinus Torvalds 	}
24155cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
24165cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
24175cb2fc06SFUJITA Tomonori 		if (!open_devip) {
24181da177e4SLinus Torvalds 			printk(KERN_ERR "%s: out of memory at line %d\n",
2419cadbd4a5SHarvey Harrison 				__func__, __LINE__);
24201da177e4SLinus Torvalds 			return NULL;
24211da177e4SLinus Torvalds 		}
24221da177e4SLinus Torvalds 	}
2423a75869d1SFUJITA Tomonori 
24241da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
24251da177e4SLinus Torvalds 	open_devip->target = sdev->id;
24261da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
24271da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
24281da177e4SLinus Torvalds 	open_devip->reset = 1;
24291da177e4SLinus Torvalds 	open_devip->used = 1;
24301da177e4SLinus Torvalds 	memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
24311da177e4SLinus Torvalds 	if (scsi_debug_dsense)
24321da177e4SLinus Torvalds 		open_devip->sense_buff[0] = 0x72;
24331da177e4SLinus Torvalds 	else {
24341da177e4SLinus Torvalds 		open_devip->sense_buff[0] = 0x70;
24351da177e4SLinus Torvalds 		open_devip->sense_buff[7] = 0xa;
24361da177e4SLinus Torvalds 	}
2437c65b1445SDouglas Gilbert 	if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2438c65b1445SDouglas Gilbert 		open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
2439a75869d1SFUJITA Tomonori 
24401da177e4SLinus Torvalds 	return open_devip;
24411da177e4SLinus Torvalds }
24421da177e4SLinus Torvalds 
24438dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
24441da177e4SLinus Torvalds {
24458dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
24468dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
24478dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
244875ad23bcSNick Piggin 	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
24498dea0d02SFUJITA Tomonori 	return 0;
24508dea0d02SFUJITA Tomonori }
24511da177e4SLinus Torvalds 
24528dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
24538dea0d02SFUJITA Tomonori {
24548dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip;
2455a34c4e98SFUJITA Tomonori 
24561da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
24578dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
24588dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
24598dea0d02SFUJITA Tomonori 	if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
24608dea0d02SFUJITA Tomonori 		sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
24618dea0d02SFUJITA Tomonori 	devip = devInfoReg(sdp);
24628dea0d02SFUJITA Tomonori 	if (NULL == devip)
24638dea0d02SFUJITA Tomonori 		return 1;	/* no resources, will be marked offline */
24648dea0d02SFUJITA Tomonori 	sdp->hostdata = devip;
24658dea0d02SFUJITA Tomonori 	if (sdp->host->cmd_per_lun)
24668dea0d02SFUJITA Tomonori 		scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
24678dea0d02SFUJITA Tomonori 					sdp->host->cmd_per_lun);
24688dea0d02SFUJITA Tomonori 	blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
246978d4e5a0SDouglas Gilbert 	if (scsi_debug_no_uld)
247078d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
24718dea0d02SFUJITA Tomonori 	return 0;
24728dea0d02SFUJITA Tomonori }
24738dea0d02SFUJITA Tomonori 
24748dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
24758dea0d02SFUJITA Tomonori {
24768dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
24778dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
24788dea0d02SFUJITA Tomonori 
24798dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
24808dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
24818dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
24828dea0d02SFUJITA Tomonori 	if (devip) {
248325985edcSLucas De Marchi 		/* make this slot available for re-use */
24848dea0d02SFUJITA Tomonori 		devip->used = 0;
24858dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
24868dea0d02SFUJITA Tomonori 	}
24878dea0d02SFUJITA Tomonori }
24888dea0d02SFUJITA Tomonori 
24898dea0d02SFUJITA Tomonori /* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
24908dea0d02SFUJITA Tomonori static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
24918dea0d02SFUJITA Tomonori {
24928dea0d02SFUJITA Tomonori 	unsigned long iflags;
24938dea0d02SFUJITA Tomonori 	int k;
24948dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
24958dea0d02SFUJITA Tomonori 
24968dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
249778d4e5a0SDouglas Gilbert 	for (k = 0; k < scsi_debug_max_queue; ++k) {
24988dea0d02SFUJITA Tomonori 		sqcp = &queued_arr[k];
24998dea0d02SFUJITA Tomonori 		if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
25008dea0d02SFUJITA Tomonori 			del_timer_sync(&sqcp->cmnd_timer);
25018dea0d02SFUJITA Tomonori 			sqcp->in_use = 0;
25028dea0d02SFUJITA Tomonori 			sqcp->a_cmnd = NULL;
25038dea0d02SFUJITA Tomonori 			break;
25048dea0d02SFUJITA Tomonori 		}
25058dea0d02SFUJITA Tomonori 	}
25068dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
250778d4e5a0SDouglas Gilbert 	return (k < scsi_debug_max_queue) ? 1 : 0;
25088dea0d02SFUJITA Tomonori }
25098dea0d02SFUJITA Tomonori 
25108dea0d02SFUJITA Tomonori /* Deletes (stops) timers of all queued commands */
25118dea0d02SFUJITA Tomonori static void stop_all_queued(void)
25128dea0d02SFUJITA Tomonori {
25138dea0d02SFUJITA Tomonori 	unsigned long iflags;
25148dea0d02SFUJITA Tomonori 	int k;
25158dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
25168dea0d02SFUJITA Tomonori 
25178dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
251878d4e5a0SDouglas Gilbert 	for (k = 0; k < scsi_debug_max_queue; ++k) {
25198dea0d02SFUJITA Tomonori 		sqcp = &queued_arr[k];
25208dea0d02SFUJITA Tomonori 		if (sqcp->in_use && sqcp->a_cmnd) {
25218dea0d02SFUJITA Tomonori 			del_timer_sync(&sqcp->cmnd_timer);
25228dea0d02SFUJITA Tomonori 			sqcp->in_use = 0;
25238dea0d02SFUJITA Tomonori 			sqcp->a_cmnd = NULL;
25248dea0d02SFUJITA Tomonori 		}
25258dea0d02SFUJITA Tomonori 	}
25268dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
25271da177e4SLinus Torvalds }
25281da177e4SLinus Torvalds 
25291da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
25301da177e4SLinus Torvalds {
25311da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25321da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: abort\n");
25331da177e4SLinus Torvalds 	++num_aborts;
25341da177e4SLinus Torvalds 	stop_queued_cmnd(SCpnt);
25351da177e4SLinus Torvalds 	return SUCCESS;
25361da177e4SLinus Torvalds }
25371da177e4SLinus Torvalds 
25381da177e4SLinus Torvalds static int scsi_debug_biosparam(struct scsi_device *sdev,
25391da177e4SLinus Torvalds 		struct block_device * bdev, sector_t capacity, int *info)
25401da177e4SLinus Torvalds {
25411da177e4SLinus Torvalds 	int res;
25421da177e4SLinus Torvalds 	unsigned char *buf;
25431da177e4SLinus Torvalds 
25441da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25451da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: biosparam\n");
25461da177e4SLinus Torvalds 	buf = scsi_bios_ptable(bdev);
25471da177e4SLinus Torvalds 	if (buf) {
25481da177e4SLinus Torvalds 		res = scsi_partsize(buf, capacity,
25491da177e4SLinus Torvalds 				    &info[2], &info[0], &info[1]);
25501da177e4SLinus Torvalds 		kfree(buf);
25511da177e4SLinus Torvalds 		if (! res)
25521da177e4SLinus Torvalds 			return res;
25531da177e4SLinus Torvalds 	}
25541da177e4SLinus Torvalds 	info[0] = sdebug_heads;
25551da177e4SLinus Torvalds 	info[1] = sdebug_sectors_per;
25561da177e4SLinus Torvalds 	info[2] = sdebug_cylinders_per;
25571da177e4SLinus Torvalds 	return 0;
25581da177e4SLinus Torvalds }
25591da177e4SLinus Torvalds 
25601da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
25611da177e4SLinus Torvalds {
25621da177e4SLinus Torvalds 	struct sdebug_dev_info * devip;
25631da177e4SLinus Torvalds 
25641da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25651da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: device_reset\n");
25661da177e4SLinus Torvalds 	++num_dev_resets;
25671da177e4SLinus Torvalds 	if (SCpnt) {
25681da177e4SLinus Torvalds 		devip = devInfoReg(SCpnt->device);
25691da177e4SLinus Torvalds 		if (devip)
25701da177e4SLinus Torvalds 			devip->reset = 1;
25711da177e4SLinus Torvalds 	}
25721da177e4SLinus Torvalds 	return SUCCESS;
25731da177e4SLinus Torvalds }
25741da177e4SLinus Torvalds 
25751da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
25761da177e4SLinus Torvalds {
25771da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
25781da177e4SLinus Torvalds         struct sdebug_dev_info * dev_info;
25791da177e4SLinus Torvalds         struct scsi_device * sdp;
25801da177e4SLinus Torvalds         struct Scsi_Host * hp;
25811da177e4SLinus Torvalds 
25821da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25831da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: bus_reset\n");
25841da177e4SLinus Torvalds 	++num_bus_resets;
25851da177e4SLinus Torvalds 	if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
2586d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
25871da177e4SLinus Torvalds 		if (sdbg_host) {
25881da177e4SLinus Torvalds 			list_for_each_entry(dev_info,
25891da177e4SLinus Torvalds                                             &sdbg_host->dev_info_list,
25901da177e4SLinus Torvalds                                             dev_list)
25911da177e4SLinus Torvalds 				dev_info->reset = 1;
25921da177e4SLinus Torvalds 		}
25931da177e4SLinus Torvalds 	}
25941da177e4SLinus Torvalds 	return SUCCESS;
25951da177e4SLinus Torvalds }
25961da177e4SLinus Torvalds 
25971da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
25981da177e4SLinus Torvalds {
25991da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
26001da177e4SLinus Torvalds         struct sdebug_dev_info * dev_info;
26011da177e4SLinus Torvalds 
26021da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
26031da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: host_reset\n");
26041da177e4SLinus Torvalds 	++num_host_resets;
26051da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
26061da177e4SLinus Torvalds         list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
26071da177e4SLinus Torvalds                 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
26081da177e4SLinus Torvalds                                     dev_list)
26091da177e4SLinus Torvalds                         dev_info->reset = 1;
26101da177e4SLinus Torvalds         }
26111da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
26121da177e4SLinus Torvalds 	stop_all_queued();
26131da177e4SLinus Torvalds 	return SUCCESS;
26141da177e4SLinus Torvalds }
26151da177e4SLinus Torvalds 
26161da177e4SLinus Torvalds /* Initializes timers in queued array */
26171da177e4SLinus Torvalds static void __init init_all_queued(void)
26181da177e4SLinus Torvalds {
26191da177e4SLinus Torvalds 	unsigned long iflags;
26201da177e4SLinus Torvalds 	int k;
26211da177e4SLinus Torvalds 	struct sdebug_queued_cmd * sqcp;
26221da177e4SLinus Torvalds 
26231da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
262478d4e5a0SDouglas Gilbert 	for (k = 0; k < scsi_debug_max_queue; ++k) {
26251da177e4SLinus Torvalds 		sqcp = &queued_arr[k];
26261da177e4SLinus Torvalds 		init_timer(&sqcp->cmnd_timer);
26271da177e4SLinus Torvalds 		sqcp->in_use = 0;
26281da177e4SLinus Torvalds 		sqcp->a_cmnd = NULL;
26291da177e4SLinus Torvalds 	}
26301da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
26311da177e4SLinus Torvalds }
26321da177e4SLinus Torvalds 
2633f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
26345f2578e5SFUJITA Tomonori 				      unsigned long store_size)
26351da177e4SLinus Torvalds {
26361da177e4SLinus Torvalds 	struct partition * pp;
26371da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
26381da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
26391da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
26401da177e4SLinus Torvalds 
26411da177e4SLinus Torvalds 	/* assume partition table already zeroed */
2642f58b0efbSFUJITA Tomonori 	if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
26431da177e4SLinus Torvalds 		return;
26441da177e4SLinus Torvalds 	if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
26451da177e4SLinus Torvalds 		scsi_debug_num_parts = SDEBUG_MAX_PARTS;
26461da177e4SLinus Torvalds 		printk(KERN_WARNING "scsi_debug:build_parts: reducing "
26471da177e4SLinus Torvalds 				    "partitions to %d\n", SDEBUG_MAX_PARTS);
26481da177e4SLinus Torvalds 	}
2649c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
26501da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
26511da177e4SLinus Torvalds 			   / scsi_debug_num_parts;
26521da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
26531da177e4SLinus Torvalds         starts[0] = sdebug_sectors_per;
26541da177e4SLinus Torvalds 	for (k = 1; k < scsi_debug_num_parts; ++k)
26551da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
26561da177e4SLinus Torvalds 			    * heads_by_sects;
26571da177e4SLinus Torvalds 	starts[scsi_debug_num_parts] = num_sectors;
26581da177e4SLinus Torvalds 	starts[scsi_debug_num_parts + 1] = 0;
26591da177e4SLinus Torvalds 
26601da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
26611da177e4SLinus Torvalds 	ramp[511] = 0xAA;
26621da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
26631da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
26641da177e4SLinus Torvalds 		start_sec = starts[k];
26651da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
26661da177e4SLinus Torvalds 		pp->boot_ind = 0;
26671da177e4SLinus Torvalds 
26681da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
26691da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
26701da177e4SLinus Torvalds 			   / sdebug_sectors_per;
26711da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
26721da177e4SLinus Torvalds 
26731da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
26741da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
26751da177e4SLinus Torvalds 			       / sdebug_sectors_per;
26761da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
26771da177e4SLinus Torvalds 
2678150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
2679150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
26801da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
26811da177e4SLinus Torvalds 	}
26821da177e4SLinus Torvalds }
26831da177e4SLinus Torvalds 
26841da177e4SLinus Torvalds static int schedule_resp(struct scsi_cmnd * cmnd,
26851da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip,
26861da177e4SLinus Torvalds 			 done_funct_t done, int scsi_result, int delta_jiff)
26871da177e4SLinus Torvalds {
26881da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
26891da177e4SLinus Torvalds 		if (scsi_result) {
26901da177e4SLinus Torvalds 			struct scsi_device * sdp = cmnd->device;
26911da177e4SLinus Torvalds 
2692c65b1445SDouglas Gilbert 			printk(KERN_INFO "scsi_debug:    <%u %u %u %u> "
2693c65b1445SDouglas Gilbert 			       "non-zero result=0x%x\n", sdp->host->host_no,
2694c65b1445SDouglas Gilbert 			       sdp->channel, sdp->id, sdp->lun, scsi_result);
26951da177e4SLinus Torvalds 		}
26961da177e4SLinus Torvalds 	}
26971da177e4SLinus Torvalds 	if (cmnd && devip) {
26981da177e4SLinus Torvalds 		/* simulate autosense by this driver */
26991da177e4SLinus Torvalds 		if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
27001da177e4SLinus Torvalds 			memcpy(cmnd->sense_buffer, devip->sense_buff,
27011da177e4SLinus Torvalds 			       (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
27021da177e4SLinus Torvalds 			       SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
27031da177e4SLinus Torvalds 	}
27041da177e4SLinus Torvalds 	if (delta_jiff <= 0) {
27051da177e4SLinus Torvalds 		if (cmnd)
27061da177e4SLinus Torvalds 			cmnd->result = scsi_result;
27071da177e4SLinus Torvalds 		if (done)
27081da177e4SLinus Torvalds 			done(cmnd);
27091da177e4SLinus Torvalds 		return 0;
27101da177e4SLinus Torvalds 	} else {
27111da177e4SLinus Torvalds 		unsigned long iflags;
27121da177e4SLinus Torvalds 		int k;
27131da177e4SLinus Torvalds 		struct sdebug_queued_cmd * sqcp = NULL;
27141da177e4SLinus Torvalds 
27151da177e4SLinus Torvalds 		spin_lock_irqsave(&queued_arr_lock, iflags);
271678d4e5a0SDouglas Gilbert 		for (k = 0; k < scsi_debug_max_queue; ++k) {
27171da177e4SLinus Torvalds 			sqcp = &queued_arr[k];
27181da177e4SLinus Torvalds 			if (! sqcp->in_use)
27191da177e4SLinus Torvalds 				break;
27201da177e4SLinus Torvalds 		}
272178d4e5a0SDouglas Gilbert 		if (k >= scsi_debug_max_queue) {
27221da177e4SLinus Torvalds 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
27231da177e4SLinus Torvalds 			printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
27241da177e4SLinus Torvalds 			return 1;	/* report busy to mid level */
27251da177e4SLinus Torvalds 		}
27261da177e4SLinus Torvalds 		sqcp->in_use = 1;
27271da177e4SLinus Torvalds 		sqcp->a_cmnd = cmnd;
27281da177e4SLinus Torvalds 		sqcp->scsi_result = scsi_result;
27291da177e4SLinus Torvalds 		sqcp->done_funct = done;
27301da177e4SLinus Torvalds 		sqcp->cmnd_timer.function = timer_intr_handler;
27311da177e4SLinus Torvalds 		sqcp->cmnd_timer.data = k;
27321da177e4SLinus Torvalds 		sqcp->cmnd_timer.expires = jiffies + delta_jiff;
27331da177e4SLinus Torvalds 		add_timer(&sqcp->cmnd_timer);
27341da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
27351da177e4SLinus Torvalds 		if (cmnd)
27361da177e4SLinus Torvalds 			cmnd->result = 0;
27371da177e4SLinus Torvalds 		return 0;
27381da177e4SLinus Torvalds 	}
27391da177e4SLinus Torvalds }
274023183910SDouglas Gilbert /* Note: The following macros create attribute files in the
274123183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
274223183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
274323183910SDouglas Gilbert    as it can when the corresponding attribute in the
274423183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
274523183910SDouglas Gilbert  */
2746c65b1445SDouglas Gilbert module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
27475b94e232SMartin K. Petersen module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
2748c65b1445SDouglas Gilbert module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2749c65b1445SDouglas Gilbert module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
27505b94e232SMartin K. Petersen module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
27515b94e232SMartin K. Petersen module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
2752c65b1445SDouglas Gilbert module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2753c65b1445SDouglas Gilbert module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
275423183910SDouglas Gilbert module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
275568aee7baSAkinobu Mita module_param_named(guard, scsi_debug_guard, uint, S_IRUGO);
27565b94e232SMartin K. Petersen module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO);
27575b94e232SMartin K. Petersen module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO);
27585b94e232SMartin K. Petersen module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO);
2759be1dd78dSEric Sandeen module_param_named(lbprz, scsi_debug_lbprz, int, S_IRUGO);
27605b94e232SMartin K. Petersen module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
2761c65b1445SDouglas Gilbert module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
276278d4e5a0SDouglas Gilbert module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);
2763c65b1445SDouglas Gilbert module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
276478d4e5a0SDouglas Gilbert module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);
2765c65b1445SDouglas Gilbert module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2766c65b1445SDouglas Gilbert module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
27675b94e232SMartin K. Petersen module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO);
2768c65b1445SDouglas Gilbert module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
27695b94e232SMartin K. Petersen module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
2770c65b1445SDouglas Gilbert module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2771d986788bSMartin Pitt module_param_named(removable, scsi_debug_removable, bool, S_IRUGO | S_IWUSR);
2772c65b1445SDouglas Gilbert module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
27735b94e232SMartin K. Petersen module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
27745b94e232SMartin K. Petersen module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
27755b94e232SMartin K. Petersen module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
27765b94e232SMartin K. Petersen module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
27775b94e232SMartin K. Petersen module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
2778c65b1445SDouglas Gilbert module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
277923183910SDouglas Gilbert module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
278023183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
27815b94e232SMartin K. Petersen module_param_named(write_same_length, scsi_debug_write_same_length, int,
27825b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
27831da177e4SLinus Torvalds 
27841da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
27851da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
27861da177e4SLinus Torvalds MODULE_LICENSE("GPL");
27871da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION);
27881da177e4SLinus Torvalds 
27891da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
27905b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
27911da177e4SLinus Torvalds MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
2792c65b1445SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
27935b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
27945b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
2795c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
2796beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
279723183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
27985b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
27995b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
28005b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
28015b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
2802be1dd78dSEric Sandeen MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
28035b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
2804c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
280578d4e5a0SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to 255(def))");
2806c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
280778d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
28081da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
2809c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
28105b94e232SMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
28116f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
28125b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
28131da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2814d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
28151da177e4SLinus Torvalds MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
2816ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
28175b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
28185b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
28196014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
28206014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
28215b94e232SMartin K. Petersen MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
28225b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
28235b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
28241da177e4SLinus Torvalds 
28251da177e4SLinus Torvalds static char sdebug_info[256];
28261da177e4SLinus Torvalds 
28271da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp)
28281da177e4SLinus Torvalds {
28291da177e4SLinus Torvalds 	sprintf(sdebug_info, "scsi_debug, version %s [%s], "
28301da177e4SLinus Torvalds 		"dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
28311da177e4SLinus Torvalds 		scsi_debug_version_date, scsi_debug_dev_size_mb,
28321da177e4SLinus Torvalds 		scsi_debug_opts);
28331da177e4SLinus Torvalds 	return sdebug_info;
28341da177e4SLinus Torvalds }
28351da177e4SLinus Torvalds 
28361da177e4SLinus Torvalds /* scsi_debug_proc_info
28371da177e4SLinus Torvalds  * Used if the driver currently has no own support for /proc/scsi
28381da177e4SLinus Torvalds  */
2839c8ed555aSAl Viro static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, int length)
28401da177e4SLinus Torvalds {
28411da177e4SLinus Torvalds 	char arr[16];
2842c8ed555aSAl Viro 	int opts;
28431da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
28441da177e4SLinus Torvalds 
28451da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
28461da177e4SLinus Torvalds 		return -EACCES;
28471da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
28481da177e4SLinus Torvalds 	arr[minLen] = '\0';
2849c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
28501da177e4SLinus Torvalds 		return -EINVAL;
2851c8ed555aSAl Viro 	scsi_debug_opts = opts;
28521da177e4SLinus Torvalds 	if (scsi_debug_every_nth != 0)
28531da177e4SLinus Torvalds 		scsi_debug_cmnd_count = 0;
28541da177e4SLinus Torvalds 	return length;
28551da177e4SLinus Torvalds }
2856c8ed555aSAl Viro 
2857c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
2858c8ed555aSAl Viro {
2859c8ed555aSAl Viro 	seq_printf(m, "scsi_debug adapter driver, version "
28601da177e4SLinus Torvalds 	    "%s [%s]\n"
28611da177e4SLinus Torvalds 	    "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
28621da177e4SLinus Torvalds 	    "every_nth=%d(curr:%d)\n"
28631da177e4SLinus Torvalds 	    "delay=%d, max_luns=%d, scsi_level=%d\n"
28641da177e4SLinus Torvalds 	    "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
28651da177e4SLinus Torvalds 	    "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2866c6a44287SMartin K. Petersen 	    "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n",
28671da177e4SLinus Torvalds 	    SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
28681da177e4SLinus Torvalds 	    scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
28691da177e4SLinus Torvalds 	    scsi_debug_cmnd_count, scsi_debug_delay,
28701da177e4SLinus Torvalds 	    scsi_debug_max_luns, scsi_debug_scsi_level,
2871597136abSMartin K. Petersen 	    scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
2872597136abSMartin K. Petersen 	    sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
2873c6a44287SMartin K. Petersen 	    num_host_resets, dix_reads, dix_writes, dif_errors);
2874c8ed555aSAl Viro 	return 0;
28751da177e4SLinus Torvalds }
28761da177e4SLinus Torvalds 
287782069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
28781da177e4SLinus Torvalds {
28791da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
28801da177e4SLinus Torvalds }
28811da177e4SLinus Torvalds 
288282069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
288382069379SAkinobu Mita 			   size_t count)
28841da177e4SLinus Torvalds {
28851da177e4SLinus Torvalds         int delay;
28861da177e4SLinus Torvalds 	char work[20];
28871da177e4SLinus Torvalds 
28881da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
28891da177e4SLinus Torvalds 		if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
28901da177e4SLinus Torvalds 			scsi_debug_delay = delay;
28911da177e4SLinus Torvalds 			return count;
28921da177e4SLinus Torvalds 		}
28931da177e4SLinus Torvalds 	}
28941da177e4SLinus Torvalds 	return -EINVAL;
28951da177e4SLinus Torvalds }
289682069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
28971da177e4SLinus Torvalds 
289882069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
28991da177e4SLinus Torvalds {
29001da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
29011da177e4SLinus Torvalds }
29021da177e4SLinus Torvalds 
290382069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
290482069379SAkinobu Mita 			  size_t count)
29051da177e4SLinus Torvalds {
29061da177e4SLinus Torvalds         int opts;
29071da177e4SLinus Torvalds 	char work[20];
29081da177e4SLinus Torvalds 
29091da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
29101da177e4SLinus Torvalds 		if (0 == strnicmp(work,"0x", 2)) {
29111da177e4SLinus Torvalds 			if (1 == sscanf(&work[2], "%x", &opts))
29121da177e4SLinus Torvalds 				goto opts_done;
29131da177e4SLinus Torvalds 		} else {
29141da177e4SLinus Torvalds 			if (1 == sscanf(work, "%d", &opts))
29151da177e4SLinus Torvalds 				goto opts_done;
29161da177e4SLinus Torvalds 		}
29171da177e4SLinus Torvalds 	}
29181da177e4SLinus Torvalds 	return -EINVAL;
29191da177e4SLinus Torvalds opts_done:
29201da177e4SLinus Torvalds 	scsi_debug_opts = opts;
29211da177e4SLinus Torvalds 	scsi_debug_cmnd_count = 0;
29221da177e4SLinus Torvalds 	return count;
29231da177e4SLinus Torvalds }
292482069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
29251da177e4SLinus Torvalds 
292682069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
29271da177e4SLinus Torvalds {
29281da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
29291da177e4SLinus Torvalds }
293082069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
293182069379SAkinobu Mita 			   size_t count)
29321da177e4SLinus Torvalds {
29331da177e4SLinus Torvalds         int n;
29341da177e4SLinus Torvalds 
29351da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
29361da177e4SLinus Torvalds 		scsi_debug_ptype = n;
29371da177e4SLinus Torvalds 		return count;
29381da177e4SLinus Torvalds 	}
29391da177e4SLinus Torvalds 	return -EINVAL;
29401da177e4SLinus Torvalds }
294182069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
29421da177e4SLinus Torvalds 
294382069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
29441da177e4SLinus Torvalds {
29451da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
29461da177e4SLinus Torvalds }
294782069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
294882069379SAkinobu Mita 			    size_t count)
29491da177e4SLinus Torvalds {
29501da177e4SLinus Torvalds         int n;
29511da177e4SLinus Torvalds 
29521da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
29531da177e4SLinus Torvalds 		scsi_debug_dsense = n;
29541da177e4SLinus Torvalds 		return count;
29551da177e4SLinus Torvalds 	}
29561da177e4SLinus Torvalds 	return -EINVAL;
29571da177e4SLinus Torvalds }
295882069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
29591da177e4SLinus Torvalds 
296082069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
296123183910SDouglas Gilbert {
296223183910SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
296323183910SDouglas Gilbert }
296482069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
296582069379SAkinobu Mita 			     size_t count)
296623183910SDouglas Gilbert {
296723183910SDouglas Gilbert         int n;
296823183910SDouglas Gilbert 
296923183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
297023183910SDouglas Gilbert 		scsi_debug_fake_rw = n;
297123183910SDouglas Gilbert 		return count;
297223183910SDouglas Gilbert 	}
297323183910SDouglas Gilbert 	return -EINVAL;
297423183910SDouglas Gilbert }
297582069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
297623183910SDouglas Gilbert 
297782069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
2978c65b1445SDouglas Gilbert {
2979c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2980c65b1445SDouglas Gilbert }
298182069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
298282069379SAkinobu Mita 			      size_t count)
2983c65b1445SDouglas Gilbert {
2984c65b1445SDouglas Gilbert         int n;
2985c65b1445SDouglas Gilbert 
2986c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2987c65b1445SDouglas Gilbert 		scsi_debug_no_lun_0 = n;
2988c65b1445SDouglas Gilbert 		return count;
2989c65b1445SDouglas Gilbert 	}
2990c65b1445SDouglas Gilbert 	return -EINVAL;
2991c65b1445SDouglas Gilbert }
299282069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
2993c65b1445SDouglas Gilbert 
299482069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
29951da177e4SLinus Torvalds {
29961da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
29971da177e4SLinus Torvalds }
299882069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
299982069379SAkinobu Mita 			      size_t count)
30001da177e4SLinus Torvalds {
30011da177e4SLinus Torvalds         int n;
30021da177e4SLinus Torvalds 
30031da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
30041da177e4SLinus Torvalds 		scsi_debug_num_tgts = n;
30051da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
30061da177e4SLinus Torvalds 		return count;
30071da177e4SLinus Torvalds 	}
30081da177e4SLinus Torvalds 	return -EINVAL;
30091da177e4SLinus Torvalds }
301082069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
30111da177e4SLinus Torvalds 
301282069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
30131da177e4SLinus Torvalds {
30141da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
30151da177e4SLinus Torvalds }
301682069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
30171da177e4SLinus Torvalds 
301882069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
30191da177e4SLinus Torvalds {
30201da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
30211da177e4SLinus Torvalds }
302282069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
30231da177e4SLinus Torvalds 
302482069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
30251da177e4SLinus Torvalds {
30261da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
30271da177e4SLinus Torvalds }
302882069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
302982069379SAkinobu Mita 			       size_t count)
30301da177e4SLinus Torvalds {
30311da177e4SLinus Torvalds         int nth;
30321da177e4SLinus Torvalds 
30331da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
30341da177e4SLinus Torvalds 		scsi_debug_every_nth = nth;
30351da177e4SLinus Torvalds 		scsi_debug_cmnd_count = 0;
30361da177e4SLinus Torvalds 		return count;
30371da177e4SLinus Torvalds 	}
30381da177e4SLinus Torvalds 	return -EINVAL;
30391da177e4SLinus Torvalds }
304082069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
30411da177e4SLinus Torvalds 
304282069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
30431da177e4SLinus Torvalds {
30441da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
30451da177e4SLinus Torvalds }
304682069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
304782069379SAkinobu Mita 			      size_t count)
30481da177e4SLinus Torvalds {
30491da177e4SLinus Torvalds         int n;
30501da177e4SLinus Torvalds 
30511da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
30521da177e4SLinus Torvalds 		scsi_debug_max_luns = n;
30531da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
30541da177e4SLinus Torvalds 		return count;
30551da177e4SLinus Torvalds 	}
30561da177e4SLinus Torvalds 	return -EINVAL;
30571da177e4SLinus Torvalds }
305882069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
30591da177e4SLinus Torvalds 
306082069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
306178d4e5a0SDouglas Gilbert {
306278d4e5a0SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue);
306378d4e5a0SDouglas Gilbert }
306482069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
306582069379SAkinobu Mita 			       size_t count)
306678d4e5a0SDouglas Gilbert {
306778d4e5a0SDouglas Gilbert         int n;
306878d4e5a0SDouglas Gilbert 
306978d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
307078d4e5a0SDouglas Gilbert 	    (n <= SCSI_DEBUG_CANQUEUE)) {
307178d4e5a0SDouglas Gilbert 		scsi_debug_max_queue = n;
307278d4e5a0SDouglas Gilbert 		return count;
307378d4e5a0SDouglas Gilbert 	}
307478d4e5a0SDouglas Gilbert 	return -EINVAL;
307578d4e5a0SDouglas Gilbert }
307682069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
307778d4e5a0SDouglas Gilbert 
307882069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
307978d4e5a0SDouglas Gilbert {
308078d4e5a0SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld);
308178d4e5a0SDouglas Gilbert }
308282069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
308378d4e5a0SDouglas Gilbert 
308482069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
30851da177e4SLinus Torvalds {
30861da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
30871da177e4SLinus Torvalds }
308882069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
30891da177e4SLinus Torvalds 
309082069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
3091c65b1445SDouglas Gilbert {
3092c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
3093c65b1445SDouglas Gilbert }
309482069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
309582069379SAkinobu Mita 				size_t count)
3096c65b1445SDouglas Gilbert {
3097c65b1445SDouglas Gilbert         int n;
3098c65b1445SDouglas Gilbert 
3099c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3100c65b1445SDouglas Gilbert 		scsi_debug_virtual_gb = n;
310128898873SFUJITA Tomonori 
310228898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
310328898873SFUJITA Tomonori 
3104c65b1445SDouglas Gilbert 		return count;
3105c65b1445SDouglas Gilbert 	}
3106c65b1445SDouglas Gilbert 	return -EINVAL;
3107c65b1445SDouglas Gilbert }
310882069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
3109c65b1445SDouglas Gilbert 
311082069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
31111da177e4SLinus Torvalds {
31121da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
31131da177e4SLinus Torvalds }
31141da177e4SLinus Torvalds 
311582069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
311682069379SAkinobu Mita 			      size_t count)
31171da177e4SLinus Torvalds {
31181da177e4SLinus Torvalds 	int delta_hosts;
31191da177e4SLinus Torvalds 
3120f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
31211da177e4SLinus Torvalds 		return -EINVAL;
31221da177e4SLinus Torvalds 	if (delta_hosts > 0) {
31231da177e4SLinus Torvalds 		do {
31241da177e4SLinus Torvalds 			sdebug_add_adapter();
31251da177e4SLinus Torvalds 		} while (--delta_hosts);
31261da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
31271da177e4SLinus Torvalds 		do {
31281da177e4SLinus Torvalds 			sdebug_remove_adapter();
31291da177e4SLinus Torvalds 		} while (++delta_hosts);
31301da177e4SLinus Torvalds 	}
31311da177e4SLinus Torvalds 	return count;
31321da177e4SLinus Torvalds }
313382069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
31341da177e4SLinus Torvalds 
313582069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
313623183910SDouglas Gilbert {
313723183910SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
313823183910SDouglas Gilbert }
313982069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
314082069379SAkinobu Mita 				    size_t count)
314123183910SDouglas Gilbert {
314223183910SDouglas Gilbert 	int n;
314323183910SDouglas Gilbert 
314423183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
314523183910SDouglas Gilbert 		scsi_debug_vpd_use_hostno = n;
314623183910SDouglas Gilbert 		return count;
314723183910SDouglas Gilbert 	}
314823183910SDouglas Gilbert 	return -EINVAL;
314923183910SDouglas Gilbert }
315082069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
315123183910SDouglas Gilbert 
315282069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
3153597136abSMartin K. Petersen {
3154597136abSMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
3155597136abSMartin K. Petersen }
315682069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
3157597136abSMartin K. Petersen 
315882069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
3159c6a44287SMartin K. Petersen {
3160c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
3161c6a44287SMartin K. Petersen }
316282069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
3163c6a44287SMartin K. Petersen 
316482069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
3165c6a44287SMartin K. Petersen {
3166c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
3167c6a44287SMartin K. Petersen }
316882069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
3169c6a44287SMartin K. Petersen 
317082069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
3171c6a44287SMartin K. Petersen {
317268aee7baSAkinobu Mita 	return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_guard);
3173c6a44287SMartin K. Petersen }
317482069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
3175c6a44287SMartin K. Petersen 
317682069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
3177c6a44287SMartin K. Petersen {
3178c6a44287SMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
3179c6a44287SMartin K. Petersen }
318082069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
3181c6a44287SMartin K. Petersen 
318282069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
318344d92694SMartin K. Petersen {
318444d92694SMartin K. Petersen 	ssize_t count;
318544d92694SMartin K. Petersen 
31865b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
318744d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
318844d92694SMartin K. Petersen 				 sdebug_store_sectors);
318944d92694SMartin K. Petersen 
319044d92694SMartin K. Petersen 	count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
319144d92694SMartin K. Petersen 
319244d92694SMartin K. Petersen 	buf[count++] = '\n';
319344d92694SMartin K. Petersen 	buf[count++] = 0;
319444d92694SMartin K. Petersen 
319544d92694SMartin K. Petersen 	return count;
319644d92694SMartin K. Petersen }
319782069379SAkinobu Mita static DRIVER_ATTR_RO(map);
319844d92694SMartin K. Petersen 
319982069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
3200d986788bSMartin Pitt {
3201d986788bSMartin Pitt 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_removable ? 1 : 0);
3202d986788bSMartin Pitt }
320382069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
320482069379SAkinobu Mita 			       size_t count)
3205d986788bSMartin Pitt {
3206d986788bSMartin Pitt 	int n;
3207d986788bSMartin Pitt 
3208d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3209d986788bSMartin Pitt 		scsi_debug_removable = (n > 0);
3210d986788bSMartin Pitt 		return count;
3211d986788bSMartin Pitt 	}
3212d986788bSMartin Pitt 	return -EINVAL;
3213d986788bSMartin Pitt }
321482069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
3215d986788bSMartin Pitt 
321682069379SAkinobu Mita /* Note: The following array creates attribute files in the
321723183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
321823183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
321923183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
322023183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
322123183910SDouglas Gilbert  */
32226ecaff7fSRandy Dunlap 
322382069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
322482069379SAkinobu Mita 	&driver_attr_delay.attr,
322582069379SAkinobu Mita 	&driver_attr_opts.attr,
322682069379SAkinobu Mita 	&driver_attr_ptype.attr,
322782069379SAkinobu Mita 	&driver_attr_dsense.attr,
322882069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
322982069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
323082069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
323182069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
323282069379SAkinobu Mita 	&driver_attr_num_parts.attr,
323382069379SAkinobu Mita 	&driver_attr_every_nth.attr,
323482069379SAkinobu Mita 	&driver_attr_max_luns.attr,
323582069379SAkinobu Mita 	&driver_attr_max_queue.attr,
323682069379SAkinobu Mita 	&driver_attr_no_uld.attr,
323782069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
323882069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
323982069379SAkinobu Mita 	&driver_attr_add_host.attr,
324082069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
324182069379SAkinobu Mita 	&driver_attr_sector_size.attr,
324282069379SAkinobu Mita 	&driver_attr_dix.attr,
324382069379SAkinobu Mita 	&driver_attr_dif.attr,
324482069379SAkinobu Mita 	&driver_attr_guard.attr,
324582069379SAkinobu Mita 	&driver_attr_ato.attr,
324682069379SAkinobu Mita 	&driver_attr_map.attr,
324782069379SAkinobu Mita 	&driver_attr_removable.attr,
324882069379SAkinobu Mita 	NULL,
324982069379SAkinobu Mita };
325082069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
32511da177e4SLinus Torvalds 
325211ddcecaSAkinobu Mita static struct device *pseudo_primary;
32538dea0d02SFUJITA Tomonori 
32541da177e4SLinus Torvalds static int __init scsi_debug_init(void)
32551da177e4SLinus Torvalds {
32565f2578e5SFUJITA Tomonori 	unsigned long sz;
32571da177e4SLinus Torvalds 	int host_to_add;
32581da177e4SLinus Torvalds 	int k;
32596ecaff7fSRandy Dunlap 	int ret;
32601da177e4SLinus Torvalds 
3261597136abSMartin K. Petersen 	switch (scsi_debug_sector_size) {
3262597136abSMartin K. Petersen 	case  512:
3263597136abSMartin K. Petersen 	case 1024:
3264597136abSMartin K. Petersen 	case 2048:
3265597136abSMartin K. Petersen 	case 4096:
3266597136abSMartin K. Petersen 		break;
3267597136abSMartin K. Petersen 	default:
3268c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n",
3269597136abSMartin K. Petersen 		       scsi_debug_sector_size);
3270597136abSMartin K. Petersen 		return -EINVAL;
3271597136abSMartin K. Petersen 	}
3272597136abSMartin K. Petersen 
3273c6a44287SMartin K. Petersen 	switch (scsi_debug_dif) {
3274c6a44287SMartin K. Petersen 
3275c6a44287SMartin K. Petersen 	case SD_DIF_TYPE0_PROTECTION:
3276c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
3277395cef03SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
3278c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
3279c6a44287SMartin K. Petersen 		break;
3280c6a44287SMartin K. Petersen 
3281c6a44287SMartin K. Petersen 	default:
3282395cef03SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n");
3283c6a44287SMartin K. Petersen 		return -EINVAL;
3284c6a44287SMartin K. Petersen 	}
3285c6a44287SMartin K. Petersen 
3286c6a44287SMartin K. Petersen 	if (scsi_debug_guard > 1) {
3287c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n");
3288c6a44287SMartin K. Petersen 		return -EINVAL;
3289c6a44287SMartin K. Petersen 	}
3290c6a44287SMartin K. Petersen 
3291c6a44287SMartin K. Petersen 	if (scsi_debug_ato > 1) {
3292c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n");
3293c6a44287SMartin K. Petersen 		return -EINVAL;
3294c6a44287SMartin K. Petersen 	}
3295c6a44287SMartin K. Petersen 
3296ea61fca5SMartin K. Petersen 	if (scsi_debug_physblk_exp > 15) {
3297ea61fca5SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n",
3298ea61fca5SMartin K. Petersen 		       scsi_debug_physblk_exp);
3299ea61fca5SMartin K. Petersen 		return -EINVAL;
3300ea61fca5SMartin K. Petersen 	}
3301ea61fca5SMartin K. Petersen 
3302ea61fca5SMartin K. Petersen 	if (scsi_debug_lowest_aligned > 0x3fff) {
3303ea61fca5SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n",
3304ea61fca5SMartin K. Petersen 		       scsi_debug_lowest_aligned);
3305ea61fca5SMartin K. Petersen 		return -EINVAL;
3306ea61fca5SMartin K. Petersen 	}
3307ea61fca5SMartin K. Petersen 
33081da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb < 1)
33091da177e4SLinus Torvalds 		scsi_debug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
33105f2578e5SFUJITA Tomonori 	sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
3311597136abSMartin K. Petersen 	sdebug_store_sectors = sz / scsi_debug_sector_size;
331228898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
33131da177e4SLinus Torvalds 
33141da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
33151da177e4SLinus Torvalds 	sdebug_heads = 8;
33161da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
33171da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb >= 16)
33181da177e4SLinus Torvalds 		sdebug_heads = 32;
33191da177e4SLinus Torvalds 	else if (scsi_debug_dev_size_mb >= 256)
33201da177e4SLinus Torvalds 		sdebug_heads = 64;
33211da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
33221da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
33231da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
33241da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
33251da177e4SLinus Torvalds 		sdebug_heads = 255;
33261da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
33271da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
33281da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
33291da177e4SLinus Torvalds 	}
33301da177e4SLinus Torvalds 
33311da177e4SLinus Torvalds 	fake_storep = vmalloc(sz);
33321da177e4SLinus Torvalds 	if (NULL == fake_storep) {
33331da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
33341da177e4SLinus Torvalds 		return -ENOMEM;
33351da177e4SLinus Torvalds 	}
33361da177e4SLinus Torvalds 	memset(fake_storep, 0, sz);
33371da177e4SLinus Torvalds 	if (scsi_debug_num_parts > 0)
3338f58b0efbSFUJITA Tomonori 		sdebug_build_parts(fake_storep, sz);
33391da177e4SLinus Torvalds 
33407cb69d03SAkinobu Mita 	if (scsi_debug_dix) {
3341c6a44287SMartin K. Petersen 		int dif_size;
3342c6a44287SMartin K. Petersen 
3343c6a44287SMartin K. Petersen 		dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
3344c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
3345c6a44287SMartin K. Petersen 
3346c6a44287SMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n",
3347c6a44287SMartin K. Petersen 		       dif_size, dif_storep);
3348c6a44287SMartin K. Petersen 
3349c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
3350c6a44287SMartin K. Petersen 			printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n");
3351c6a44287SMartin K. Petersen 			ret = -ENOMEM;
3352c6a44287SMartin K. Petersen 			goto free_vm;
3353c6a44287SMartin K. Petersen 		}
3354c6a44287SMartin K. Petersen 
3355c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
3356c6a44287SMartin K. Petersen 	}
3357c6a44287SMartin K. Petersen 
33585b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
33595b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
33606014759cSMartin K. Petersen 		scsi_debug_unmap_max_blocks =
33616014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU);
33626014759cSMartin K. Petersen 
33636014759cSMartin K. Petersen 		scsi_debug_unmap_max_desc =
33646014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_max_desc, 0U, 256U);
33656014759cSMartin K. Petersen 
33666014759cSMartin K. Petersen 		scsi_debug_unmap_granularity =
33676014759cSMartin K. Petersen 			clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU);
33686014759cSMartin K. Petersen 
33696014759cSMartin K. Petersen 		if (scsi_debug_unmap_alignment &&
3370ac17078aSAkinobu Mita 		    scsi_debug_unmap_granularity <=
3371ac17078aSAkinobu Mita 		    scsi_debug_unmap_alignment) {
337244d92694SMartin K. Petersen 			printk(KERN_ERR
3373ac17078aSAkinobu Mita 			       "%s: ERR: unmap_granularity <= unmap_alignment\n",
337444d92694SMartin K. Petersen 			       __func__);
337544d92694SMartin K. Petersen 			return -EINVAL;
337644d92694SMartin K. Petersen 		}
337744d92694SMartin K. Petersen 
3378b90ebc3dSAkinobu Mita 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
3379b90ebc3dSAkinobu Mita 		map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
338044d92694SMartin K. Petersen 
338144d92694SMartin K. Petersen 		printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n",
338244d92694SMartin K. Petersen 		       map_size);
338344d92694SMartin K. Petersen 
338444d92694SMartin K. Petersen 		if (map_storep == NULL) {
338544d92694SMartin K. Petersen 			printk(KERN_ERR "scsi_debug_init: out of mem. (MAP)\n");
338644d92694SMartin K. Petersen 			ret = -ENOMEM;
338744d92694SMartin K. Petersen 			goto free_vm;
338844d92694SMartin K. Petersen 		}
338944d92694SMartin K. Petersen 
3390b90ebc3dSAkinobu Mita 		bitmap_zero(map_storep, map_size);
339144d92694SMartin K. Petersen 
339244d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
339344d92694SMartin K. Petersen 		if (scsi_debug_num_parts)
339444d92694SMartin K. Petersen 			map_region(0, 2);
339544d92694SMartin K. Petersen 	}
339644d92694SMartin K. Petersen 
33979b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
33989b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
33999b906779SNicholas Bellinger 		printk(KERN_WARNING "scsi_debug: root_device_register() error\n");
34009b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
34016ecaff7fSRandy Dunlap 		goto free_vm;
34026ecaff7fSRandy Dunlap 	}
34036ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
34046ecaff7fSRandy Dunlap 	if (ret < 0) {
34056ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
34066ecaff7fSRandy Dunlap 			ret);
34076ecaff7fSRandy Dunlap 		goto dev_unreg;
34086ecaff7fSRandy Dunlap 	}
34096ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
34106ecaff7fSRandy Dunlap 	if (ret < 0) {
34116ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
34126ecaff7fSRandy Dunlap 			ret);
34136ecaff7fSRandy Dunlap 		goto bus_unreg;
34146ecaff7fSRandy Dunlap 	}
34151da177e4SLinus Torvalds 
34166ecaff7fSRandy Dunlap 	init_all_queued();
34171da177e4SLinus Torvalds 
34181da177e4SLinus Torvalds 	host_to_add = scsi_debug_add_host;
34191da177e4SLinus Torvalds         scsi_debug_add_host = 0;
34201da177e4SLinus Torvalds 
34211da177e4SLinus Torvalds         for (k = 0; k < host_to_add; k++) {
34221da177e4SLinus Torvalds                 if (sdebug_add_adapter()) {
34231da177e4SLinus Torvalds                         printk(KERN_ERR "scsi_debug_init: "
34241da177e4SLinus Torvalds                                "sdebug_add_adapter failed k=%d\n", k);
34251da177e4SLinus Torvalds                         break;
34261da177e4SLinus Torvalds                 }
34271da177e4SLinus Torvalds         }
34281da177e4SLinus Torvalds 
34291da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
34301da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
34311da177e4SLinus Torvalds 		       scsi_debug_add_host);
34321da177e4SLinus Torvalds 	}
34331da177e4SLinus Torvalds 	return 0;
34346ecaff7fSRandy Dunlap 
34356ecaff7fSRandy Dunlap bus_unreg:
34366ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
34376ecaff7fSRandy Dunlap dev_unreg:
34389b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
34396ecaff7fSRandy Dunlap free_vm:
344044d92694SMartin K. Petersen 	if (map_storep)
344144d92694SMartin K. Petersen 		vfree(map_storep);
3442c6a44287SMartin K. Petersen 	if (dif_storep)
3443c6a44287SMartin K. Petersen 		vfree(dif_storep);
34446ecaff7fSRandy Dunlap 	vfree(fake_storep);
34456ecaff7fSRandy Dunlap 
34466ecaff7fSRandy Dunlap 	return ret;
34471da177e4SLinus Torvalds }
34481da177e4SLinus Torvalds 
34491da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
34501da177e4SLinus Torvalds {
34511da177e4SLinus Torvalds 	int k = scsi_debug_add_host;
34521da177e4SLinus Torvalds 
34531da177e4SLinus Torvalds 	stop_all_queued();
34541da177e4SLinus Torvalds 	for (; k; k--)
34551da177e4SLinus Torvalds 		sdebug_remove_adapter();
34561da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
34571da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
34589b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
34591da177e4SLinus Torvalds 
3460c6a44287SMartin K. Petersen 	if (dif_storep)
3461c6a44287SMartin K. Petersen 		vfree(dif_storep);
3462c6a44287SMartin K. Petersen 
34631da177e4SLinus Torvalds 	vfree(fake_storep);
34641da177e4SLinus Torvalds }
34651da177e4SLinus Torvalds 
34661da177e4SLinus Torvalds device_initcall(scsi_debug_init);
34671da177e4SLinus Torvalds module_exit(scsi_debug_exit);
34681da177e4SLinus Torvalds 
34691da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev)
34701da177e4SLinus Torvalds {
34711da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
34721da177e4SLinus Torvalds 
34731da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
34741da177e4SLinus Torvalds         kfree(sdbg_host);
34751da177e4SLinus Torvalds }
34761da177e4SLinus Torvalds 
34771da177e4SLinus Torvalds static int sdebug_add_adapter(void)
34781da177e4SLinus Torvalds {
34791da177e4SLinus Torvalds 	int k, devs_per_host;
34801da177e4SLinus Torvalds         int error = 0;
34811da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
34828b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
34831da177e4SLinus Torvalds 
348424669f75SJes Sorensen         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
34851da177e4SLinus Torvalds         if (NULL == sdbg_host) {
34861da177e4SLinus Torvalds                 printk(KERN_ERR "%s: out of memory at line %d\n",
3487cadbd4a5SHarvey Harrison                        __func__, __LINE__);
34881da177e4SLinus Torvalds                 return -ENOMEM;
34891da177e4SLinus Torvalds         }
34901da177e4SLinus Torvalds 
34911da177e4SLinus Torvalds         INIT_LIST_HEAD(&sdbg_host->dev_info_list);
34921da177e4SLinus Torvalds 
34931da177e4SLinus Torvalds 	devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
34941da177e4SLinus Torvalds         for (k = 0; k < devs_per_host; k++) {
34955cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
34965cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
34971da177e4SLinus Torvalds                         printk(KERN_ERR "%s: out of memory at line %d\n",
3498cadbd4a5SHarvey Harrison                                __func__, __LINE__);
34991da177e4SLinus Torvalds                         error = -ENOMEM;
35001da177e4SLinus Torvalds 			goto clean;
35011da177e4SLinus Torvalds                 }
35021da177e4SLinus Torvalds         }
35031da177e4SLinus Torvalds 
35041da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
35051da177e4SLinus Torvalds         list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
35061da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
35071da177e4SLinus Torvalds 
35081da177e4SLinus Torvalds         sdbg_host->dev.bus = &pseudo_lld_bus;
35099b906779SNicholas Bellinger         sdbg_host->dev.parent = pseudo_primary;
35101da177e4SLinus Torvalds         sdbg_host->dev.release = &sdebug_release_adapter;
351171610f55SKay Sievers         dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
35121da177e4SLinus Torvalds 
35131da177e4SLinus Torvalds         error = device_register(&sdbg_host->dev);
35141da177e4SLinus Torvalds 
35151da177e4SLinus Torvalds         if (error)
35161da177e4SLinus Torvalds 		goto clean;
35171da177e4SLinus Torvalds 
35181da177e4SLinus Torvalds 	++scsi_debug_add_host;
35191da177e4SLinus Torvalds         return error;
35201da177e4SLinus Torvalds 
35211da177e4SLinus Torvalds clean:
35228b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
35238b40228fSFUJITA Tomonori 				 dev_list) {
35241da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
35251da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
35261da177e4SLinus Torvalds 	}
35271da177e4SLinus Torvalds 
35281da177e4SLinus Torvalds 	kfree(sdbg_host);
35291da177e4SLinus Torvalds         return error;
35301da177e4SLinus Torvalds }
35311da177e4SLinus Torvalds 
35321da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
35331da177e4SLinus Torvalds {
35341da177e4SLinus Torvalds         struct sdebug_host_info * sdbg_host = NULL;
35351da177e4SLinus Torvalds 
35361da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
35371da177e4SLinus Torvalds         if (!list_empty(&sdebug_host_list)) {
35381da177e4SLinus Torvalds                 sdbg_host = list_entry(sdebug_host_list.prev,
35391da177e4SLinus Torvalds                                        struct sdebug_host_info, host_list);
35401da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
35411da177e4SLinus Torvalds 	}
35421da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
35431da177e4SLinus Torvalds 
35441da177e4SLinus Torvalds 	if (!sdbg_host)
35451da177e4SLinus Torvalds 		return;
35461da177e4SLinus Torvalds 
35471da177e4SLinus Torvalds         device_unregister(&sdbg_host->dev);
35481da177e4SLinus Torvalds         --scsi_debug_add_host;
35491da177e4SLinus Torvalds }
35501da177e4SLinus Torvalds 
3551639db475SFUJITA Tomonori static
3552f281233dSJeff Garzik int scsi_debug_queuecommand_lck(struct scsi_cmnd *SCpnt, done_funct_t done)
3553639db475SFUJITA Tomonori {
3554639db475SFUJITA Tomonori 	unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
3555639db475SFUJITA Tomonori 	int len, k;
3556639db475SFUJITA Tomonori 	unsigned int num;
3557639db475SFUJITA Tomonori 	unsigned long long lba;
3558395cef03SMartin K. Petersen 	u32 ei_lba;
3559639db475SFUJITA Tomonori 	int errsts = 0;
3560639db475SFUJITA Tomonori 	int target = SCpnt->device->id;
3561639db475SFUJITA Tomonori 	struct sdebug_dev_info *devip = NULL;
3562639db475SFUJITA Tomonori 	int inj_recovered = 0;
3563639db475SFUJITA Tomonori 	int inj_transport = 0;
3564c6a44287SMartin K. Petersen 	int inj_dif = 0;
3565c6a44287SMartin K. Petersen 	int inj_dix = 0;
3566639db475SFUJITA Tomonori 	int delay_override = 0;
356744d92694SMartin K. Petersen 	int unmap = 0;
3568639db475SFUJITA Tomonori 
3569639db475SFUJITA Tomonori 	scsi_set_resid(SCpnt, 0);
3570639db475SFUJITA Tomonori 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
3571639db475SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: cmd ");
3572639db475SFUJITA Tomonori 		for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
3573639db475SFUJITA Tomonori 			printk("%02x ", (int)cmd[k]);
3574639db475SFUJITA Tomonori 		printk("\n");
3575639db475SFUJITA Tomonori 	}
3576639db475SFUJITA Tomonori 
3577639db475SFUJITA Tomonori 	if (target == SCpnt->device->host->hostt->this_id) {
3578639db475SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: initiator's id used as "
3579639db475SFUJITA Tomonori 		       "target!\n");
3580639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
3581639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
3582639db475SFUJITA Tomonori 	}
3583639db475SFUJITA Tomonori 
3584639db475SFUJITA Tomonori 	if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
3585639db475SFUJITA Tomonori 	    (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
3586639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
3587639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
3588639db475SFUJITA Tomonori 	devip = devInfoReg(SCpnt->device);
3589639db475SFUJITA Tomonori 	if (NULL == devip)
3590639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
3591639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
3592639db475SFUJITA Tomonori 
3593639db475SFUJITA Tomonori 	if ((scsi_debug_every_nth != 0) &&
3594639db475SFUJITA Tomonori 	    (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
3595639db475SFUJITA Tomonori 		scsi_debug_cmnd_count = 0;
3596639db475SFUJITA Tomonori 		if (scsi_debug_every_nth < -1)
3597639db475SFUJITA Tomonori 			scsi_debug_every_nth = -1;
3598639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
3599639db475SFUJITA Tomonori 			return 0; /* ignore command causing timeout */
360018a4d0a2SMartin K. Petersen 		else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts &&
360118a4d0a2SMartin K. Petersen 			 scsi_medium_access_command(SCpnt))
360218a4d0a2SMartin K. Petersen 			return 0; /* time out reads and writes */
3603639db475SFUJITA Tomonori 		else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
3604639db475SFUJITA Tomonori 			inj_recovered = 1; /* to reads and writes below */
3605639db475SFUJITA Tomonori 		else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
3606639db475SFUJITA Tomonori 			inj_transport = 1; /* to reads and writes below */
3607c6a44287SMartin K. Petersen 		else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
3608c6a44287SMartin K. Petersen 			inj_dif = 1; /* to reads and writes below */
3609c6a44287SMartin K. Petersen 		else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
3610c6a44287SMartin K. Petersen 			inj_dix = 1; /* to reads and writes below */
3611639db475SFUJITA Tomonori 	}
3612639db475SFUJITA Tomonori 
3613639db475SFUJITA Tomonori 	if (devip->wlun) {
3614639db475SFUJITA Tomonori 		switch (*cmd) {
3615639db475SFUJITA Tomonori 		case INQUIRY:
3616639db475SFUJITA Tomonori 		case REQUEST_SENSE:
3617639db475SFUJITA Tomonori 		case TEST_UNIT_READY:
3618639db475SFUJITA Tomonori 		case REPORT_LUNS:
3619639db475SFUJITA Tomonori 			break;  /* only allowable wlun commands */
3620639db475SFUJITA Tomonori 		default:
3621639db475SFUJITA Tomonori 			if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3622639db475SFUJITA Tomonori 				printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
3623639db475SFUJITA Tomonori 				       "not supported for wlun\n", *cmd);
3624639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3625639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
3626639db475SFUJITA Tomonori 			errsts = check_condition_result;
3627639db475SFUJITA Tomonori 			return schedule_resp(SCpnt, devip, done, errsts,
3628639db475SFUJITA Tomonori 					     0);
3629639db475SFUJITA Tomonori 		}
3630639db475SFUJITA Tomonori 	}
3631639db475SFUJITA Tomonori 
3632639db475SFUJITA Tomonori 	switch (*cmd) {
3633639db475SFUJITA Tomonori 	case INQUIRY:     /* mandatory, ignore unit attention */
3634639db475SFUJITA Tomonori 		delay_override = 1;
3635639db475SFUJITA Tomonori 		errsts = resp_inquiry(SCpnt, target, devip);
3636639db475SFUJITA Tomonori 		break;
3637639db475SFUJITA Tomonori 	case REQUEST_SENSE:	/* mandatory, ignore unit attention */
3638639db475SFUJITA Tomonori 		delay_override = 1;
3639639db475SFUJITA Tomonori 		errsts = resp_requests(SCpnt, devip);
3640639db475SFUJITA Tomonori 		break;
3641639db475SFUJITA Tomonori 	case REZERO_UNIT:	/* actually this is REWIND for SSC */
3642639db475SFUJITA Tomonori 	case START_STOP:
3643639db475SFUJITA Tomonori 		errsts = resp_start_stop(SCpnt, devip);
3644639db475SFUJITA Tomonori 		break;
3645639db475SFUJITA Tomonori 	case ALLOW_MEDIUM_REMOVAL:
3646639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3647639db475SFUJITA Tomonori 		if (errsts)
3648639db475SFUJITA Tomonori 			break;
3649639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3650639db475SFUJITA Tomonori 			printk(KERN_INFO "scsi_debug: Medium removal %s\n",
3651639db475SFUJITA Tomonori 			       cmd[4] ? "inhibited" : "enabled");
3652639db475SFUJITA Tomonori 		break;
3653639db475SFUJITA Tomonori 	case SEND_DIAGNOSTIC:     /* mandatory */
3654639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3655639db475SFUJITA Tomonori 		break;
3656639db475SFUJITA Tomonori 	case TEST_UNIT_READY:     /* mandatory */
3657639db475SFUJITA Tomonori 		delay_override = 1;
3658639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3659639db475SFUJITA Tomonori 		break;
3660639db475SFUJITA Tomonori 	case RESERVE:
3661639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3662639db475SFUJITA Tomonori 		break;
3663639db475SFUJITA Tomonori 	case RESERVE_10:
3664639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3665639db475SFUJITA Tomonori 		break;
3666639db475SFUJITA Tomonori 	case RELEASE:
3667639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3668639db475SFUJITA Tomonori 		break;
3669639db475SFUJITA Tomonori 	case RELEASE_10:
3670639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3671639db475SFUJITA Tomonori 		break;
3672639db475SFUJITA Tomonori 	case READ_CAPACITY:
3673639db475SFUJITA Tomonori 		errsts = resp_readcap(SCpnt, devip);
3674639db475SFUJITA Tomonori 		break;
3675639db475SFUJITA Tomonori 	case SERVICE_ACTION_IN:
367644d92694SMartin K. Petersen 		if (cmd[1] == SAI_READ_CAPACITY_16)
367744d92694SMartin K. Petersen 			errsts = resp_readcap16(SCpnt, devip);
367844d92694SMartin K. Petersen 		else if (cmd[1] == SAI_GET_LBA_STATUS) {
367944d92694SMartin K. Petersen 
36805b94e232SMartin K. Petersen 			if (scsi_debug_lbp() == 0) {
368144d92694SMartin K. Petersen 				mk_sense_buffer(devip, ILLEGAL_REQUEST,
368244d92694SMartin K. Petersen 						INVALID_COMMAND_OPCODE, 0);
368344d92694SMartin K. Petersen 				errsts = check_condition_result;
368444d92694SMartin K. Petersen 			} else
368544d92694SMartin K. Petersen 				errsts = resp_get_lba_status(SCpnt, devip);
368644d92694SMartin K. Petersen 		} else {
3687639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3688639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
3689639db475SFUJITA Tomonori 			errsts = check_condition_result;
3690639db475SFUJITA Tomonori 		}
3691639db475SFUJITA Tomonori 		break;
3692639db475SFUJITA Tomonori 	case MAINTENANCE_IN:
3693639db475SFUJITA Tomonori 		if (MI_REPORT_TARGET_PGS != cmd[1]) {
3694639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3695639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
3696639db475SFUJITA Tomonori 			errsts = check_condition_result;
3697639db475SFUJITA Tomonori 			break;
3698639db475SFUJITA Tomonori 		}
3699639db475SFUJITA Tomonori 		errsts = resp_report_tgtpgs(SCpnt, devip);
3700639db475SFUJITA Tomonori 		break;
3701639db475SFUJITA Tomonori 	case READ_16:
3702639db475SFUJITA Tomonori 	case READ_12:
3703639db475SFUJITA Tomonori 	case READ_10:
3704395cef03SMartin K. Petersen 		/* READ{10,12,16} and DIF Type 2 are natural enemies */
3705395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3706395cef03SMartin K. Petersen 		    cmd[1] & 0xe0) {
3707395cef03SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3708395cef03SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
3709395cef03SMartin K. Petersen 			errsts = check_condition_result;
3710395cef03SMartin K. Petersen 			break;
3711395cef03SMartin K. Petersen 		}
3712395cef03SMartin K. Petersen 
3713395cef03SMartin K. Petersen 		if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3714395cef03SMartin K. Petersen 		     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3715395cef03SMartin K. Petersen 		    (cmd[1] & 0xe0) == 0)
3716395cef03SMartin K. Petersen 			printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3717395cef03SMartin K. Petersen 
3718395cef03SMartin K. Petersen 		/* fall through */
3719639db475SFUJITA Tomonori 	case READ_6:
3720395cef03SMartin K. Petersen read:
3721639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3722639db475SFUJITA Tomonori 		if (errsts)
3723639db475SFUJITA Tomonori 			break;
3724639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
3725639db475SFUJITA Tomonori 			break;
3726395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3727395cef03SMartin K. Petersen 		errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
3728639db475SFUJITA Tomonori 		if (inj_recovered && (0 == errsts)) {
3729639db475SFUJITA Tomonori 			mk_sense_buffer(devip, RECOVERED_ERROR,
3730639db475SFUJITA Tomonori 					THRESHOLD_EXCEEDED, 0);
3731639db475SFUJITA Tomonori 			errsts = check_condition_result;
3732639db475SFUJITA Tomonori 		} else if (inj_transport && (0 == errsts)) {
3733639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ABORTED_COMMAND,
3734639db475SFUJITA Tomonori 					TRANSPORT_PROBLEM, ACK_NAK_TO);
3735639db475SFUJITA Tomonori 			errsts = check_condition_result;
3736c6a44287SMartin K. Petersen 		} else if (inj_dif && (0 == errsts)) {
3737c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3738c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3739c6a44287SMartin K. Petersen 		} else if (inj_dix && (0 == errsts)) {
3740c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3741c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3742639db475SFUJITA Tomonori 		}
3743639db475SFUJITA Tomonori 		break;
3744639db475SFUJITA Tomonori 	case REPORT_LUNS:	/* mandatory, ignore unit attention */
3745639db475SFUJITA Tomonori 		delay_override = 1;
3746639db475SFUJITA Tomonori 		errsts = resp_report_luns(SCpnt, devip);
3747639db475SFUJITA Tomonori 		break;
3748639db475SFUJITA Tomonori 	case VERIFY:		/* 10 byte SBC-2 command */
3749639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3750639db475SFUJITA Tomonori 		break;
3751639db475SFUJITA Tomonori 	case WRITE_16:
3752639db475SFUJITA Tomonori 	case WRITE_12:
3753639db475SFUJITA Tomonori 	case WRITE_10:
3754395cef03SMartin K. Petersen 		/* WRITE{10,12,16} and DIF Type 2 are natural enemies */
3755395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3756395cef03SMartin K. Petersen 		    cmd[1] & 0xe0) {
3757395cef03SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3758395cef03SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
3759395cef03SMartin K. Petersen 			errsts = check_condition_result;
3760395cef03SMartin K. Petersen 			break;
3761395cef03SMartin K. Petersen 		}
3762395cef03SMartin K. Petersen 
3763395cef03SMartin K. Petersen 		if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3764395cef03SMartin K. Petersen 		     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3765395cef03SMartin K. Petersen 		    (cmd[1] & 0xe0) == 0)
3766395cef03SMartin K. Petersen 			printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3767395cef03SMartin K. Petersen 
3768395cef03SMartin K. Petersen 		/* fall through */
3769639db475SFUJITA Tomonori 	case WRITE_6:
3770395cef03SMartin K. Petersen write:
3771639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3772639db475SFUJITA Tomonori 		if (errsts)
3773639db475SFUJITA Tomonori 			break;
3774639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
3775639db475SFUJITA Tomonori 			break;
3776395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3777395cef03SMartin K. Petersen 		errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
3778639db475SFUJITA Tomonori 		if (inj_recovered && (0 == errsts)) {
3779639db475SFUJITA Tomonori 			mk_sense_buffer(devip, RECOVERED_ERROR,
3780639db475SFUJITA Tomonori 					THRESHOLD_EXCEEDED, 0);
3781639db475SFUJITA Tomonori 			errsts = check_condition_result;
3782c6a44287SMartin K. Petersen 		} else if (inj_dif && (0 == errsts)) {
3783c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3784c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3785c6a44287SMartin K. Petersen 		} else if (inj_dix && (0 == errsts)) {
3786c6a44287SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3787c6a44287SMartin K. Petersen 			errsts = illegal_condition_result;
3788639db475SFUJITA Tomonori 		}
3789639db475SFUJITA Tomonori 		break;
379044d92694SMartin K. Petersen 	case WRITE_SAME_16:
37915b94e232SMartin K. Petersen 	case WRITE_SAME:
37926014759cSMartin K. Petersen 		if (cmd[1] & 0x8) {
37935b94e232SMartin K. Petersen 			if ((*cmd == WRITE_SAME_16 && scsi_debug_lbpws == 0) ||
37945b94e232SMartin K. Petersen 			    (*cmd == WRITE_SAME && scsi_debug_lbpws10 == 0)) {
37956014759cSMartin K. Petersen 				mk_sense_buffer(devip, ILLEGAL_REQUEST,
37966014759cSMartin K. Petersen 						INVALID_FIELD_IN_CDB, 0);
37976014759cSMartin K. Petersen 				errsts = check_condition_result;
37986014759cSMartin K. Petersen 			} else
379944d92694SMartin K. Petersen 				unmap = 1;
38006014759cSMartin K. Petersen 		}
38016014759cSMartin K. Petersen 		if (errsts)
38026014759cSMartin K. Petersen 			break;
380344d92694SMartin K. Petersen 		errsts = check_readiness(SCpnt, 0, devip);
380444d92694SMartin K. Petersen 		if (errsts)
380544d92694SMartin K. Petersen 			break;
380644d92694SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
380744d92694SMartin K. Petersen 		errsts = resp_write_same(SCpnt, lba, num, devip, ei_lba, unmap);
380844d92694SMartin K. Petersen 		break;
380944d92694SMartin K. Petersen 	case UNMAP:
381044d92694SMartin K. Petersen 		errsts = check_readiness(SCpnt, 0, devip);
381144d92694SMartin K. Petersen 		if (errsts)
381244d92694SMartin K. Petersen 			break;
381344d92694SMartin K. Petersen 
38145b94e232SMartin K. Petersen 		if (scsi_debug_unmap_max_desc == 0 || scsi_debug_lbpu == 0) {
381544d92694SMartin K. Petersen 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
381644d92694SMartin K. Petersen 					INVALID_COMMAND_OPCODE, 0);
381744d92694SMartin K. Petersen 			errsts = check_condition_result;
381844d92694SMartin K. Petersen 		} else
381944d92694SMartin K. Petersen 			errsts = resp_unmap(SCpnt, devip);
382044d92694SMartin K. Petersen 		break;
3821639db475SFUJITA Tomonori 	case MODE_SENSE:
3822639db475SFUJITA Tomonori 	case MODE_SENSE_10:
3823639db475SFUJITA Tomonori 		errsts = resp_mode_sense(SCpnt, target, devip);
3824639db475SFUJITA Tomonori 		break;
3825639db475SFUJITA Tomonori 	case MODE_SELECT:
3826639db475SFUJITA Tomonori 		errsts = resp_mode_select(SCpnt, 1, devip);
3827639db475SFUJITA Tomonori 		break;
3828639db475SFUJITA Tomonori 	case MODE_SELECT_10:
3829639db475SFUJITA Tomonori 		errsts = resp_mode_select(SCpnt, 0, devip);
3830639db475SFUJITA Tomonori 		break;
3831639db475SFUJITA Tomonori 	case LOG_SENSE:
3832639db475SFUJITA Tomonori 		errsts = resp_log_sense(SCpnt, devip);
3833639db475SFUJITA Tomonori 		break;
3834639db475SFUJITA Tomonori 	case SYNCHRONIZE_CACHE:
3835639db475SFUJITA Tomonori 		delay_override = 1;
3836639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3837639db475SFUJITA Tomonori 		break;
3838639db475SFUJITA Tomonori 	case WRITE_BUFFER:
3839639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3840639db475SFUJITA Tomonori 		break;
3841639db475SFUJITA Tomonori 	case XDWRITEREAD_10:
3842639db475SFUJITA Tomonori 		if (!scsi_bidi_cmnd(SCpnt)) {
3843639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
3844639db475SFUJITA Tomonori 					INVALID_FIELD_IN_CDB, 0);
3845639db475SFUJITA Tomonori 			errsts = check_condition_result;
3846639db475SFUJITA Tomonori 			break;
3847639db475SFUJITA Tomonori 		}
3848639db475SFUJITA Tomonori 
3849639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
3850639db475SFUJITA Tomonori 		if (errsts)
3851639db475SFUJITA Tomonori 			break;
3852639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
3853639db475SFUJITA Tomonori 			break;
3854395cef03SMartin K. Petersen 		get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3855395cef03SMartin K. Petersen 		errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
3856639db475SFUJITA Tomonori 		if (errsts)
3857639db475SFUJITA Tomonori 			break;
3858395cef03SMartin K. Petersen 		errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
3859639db475SFUJITA Tomonori 		if (errsts)
3860639db475SFUJITA Tomonori 			break;
3861639db475SFUJITA Tomonori 		errsts = resp_xdwriteread(SCpnt, lba, num, devip);
3862639db475SFUJITA Tomonori 		break;
3863395cef03SMartin K. Petersen 	case VARIABLE_LENGTH_CMD:
3864395cef03SMartin K. Petersen 		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
3865395cef03SMartin K. Petersen 
3866395cef03SMartin K. Petersen 			if ((cmd[10] & 0xe0) == 0)
3867395cef03SMartin K. Petersen 				printk(KERN_ERR
3868395cef03SMartin K. Petersen 				       "Unprotected RD/WR to DIF device\n");
3869395cef03SMartin K. Petersen 
3870395cef03SMartin K. Petersen 			if (cmd[9] == READ_32) {
3871395cef03SMartin K. Petersen 				BUG_ON(SCpnt->cmd_len < 32);
3872395cef03SMartin K. Petersen 				goto read;
3873395cef03SMartin K. Petersen 			}
3874395cef03SMartin K. Petersen 
3875395cef03SMartin K. Petersen 			if (cmd[9] == WRITE_32) {
3876395cef03SMartin K. Petersen 				BUG_ON(SCpnt->cmd_len < 32);
3877395cef03SMartin K. Petersen 				goto write;
3878395cef03SMartin K. Petersen 			}
3879395cef03SMartin K. Petersen 		}
3880395cef03SMartin K. Petersen 
3881395cef03SMartin K. Petersen 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
3882395cef03SMartin K. Petersen 				INVALID_FIELD_IN_CDB, 0);
3883395cef03SMartin K. Petersen 		errsts = check_condition_result;
3884395cef03SMartin K. Petersen 		break;
3885395cef03SMartin K. Petersen 
3886639db475SFUJITA Tomonori 	default:
3887639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3888639db475SFUJITA Tomonori 			printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
3889639db475SFUJITA Tomonori 			       "supported\n", *cmd);
3890639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
3891639db475SFUJITA Tomonori 		if (errsts)
3892639db475SFUJITA Tomonori 			break;	/* Unit attention takes precedence */
3893639db475SFUJITA Tomonori 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
3894639db475SFUJITA Tomonori 		errsts = check_condition_result;
3895639db475SFUJITA Tomonori 		break;
3896639db475SFUJITA Tomonori 	}
3897639db475SFUJITA Tomonori 	return schedule_resp(SCpnt, devip, done, errsts,
3898639db475SFUJITA Tomonori 			     (delay_override ? 0 : scsi_debug_delay));
3899639db475SFUJITA Tomonori }
3900639db475SFUJITA Tomonori 
3901f281233dSJeff Garzik static DEF_SCSI_QCMD(scsi_debug_queuecommand)
3902f281233dSJeff Garzik 
39039e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
3904c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
3905c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
39069e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
39079e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
39089e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
39099e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
39109e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
39119e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
39129e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
39139e603ca0SFUJITA Tomonori 	.queuecommand =		scsi_debug_queuecommand,
39149e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
39159e603ca0SFUJITA Tomonori 	.eh_bus_reset_handler = scsi_debug_bus_reset,
39169e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
39179e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
39189e603ca0SFUJITA Tomonori 	.bios_param =		scsi_debug_biosparam,
39199e603ca0SFUJITA Tomonori 	.can_queue =		SCSI_DEBUG_CANQUEUE,
39209e603ca0SFUJITA Tomonori 	.this_id =		7,
39219e603ca0SFUJITA Tomonori 	.sg_tablesize =		256,
39229e603ca0SFUJITA Tomonori 	.cmd_per_lun =		16,
39239e603ca0SFUJITA Tomonori 	.max_sectors =		0xffff,
39249e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
39259e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
39269e603ca0SFUJITA Tomonori };
39279e603ca0SFUJITA Tomonori 
39281da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev)
39291da177e4SLinus Torvalds {
39301da177e4SLinus Torvalds         int error = 0;
39311da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
39321da177e4SLinus Torvalds         struct Scsi_Host *hpnt;
3933c6a44287SMartin K. Petersen 	int host_prot;
39341da177e4SLinus Torvalds 
39351da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
39361da177e4SLinus Torvalds 
393778d4e5a0SDouglas Gilbert 	sdebug_driver_template.can_queue = scsi_debug_max_queue;
39381da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
39391da177e4SLinus Torvalds 	if (NULL == hpnt) {
3940cadbd4a5SHarvey Harrison 		printk(KERN_ERR "%s: scsi_register failed\n", __func__);
39411da177e4SLinus Torvalds 		error = -ENODEV;
39421da177e4SLinus Torvalds 		return error;
39431da177e4SLinus Torvalds 	}
39441da177e4SLinus Torvalds 
39451da177e4SLinus Torvalds         sdbg_host->shost = hpnt;
39461da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
39471da177e4SLinus Torvalds 	if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
39481da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts + 1;
39491da177e4SLinus Torvalds 	else
39501da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts;
3951c65b1445SDouglas Gilbert 	hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;	/* = scsi_debug_max_luns; */
39521da177e4SLinus Torvalds 
3953c6a44287SMartin K. Petersen 	host_prot = 0;
3954c6a44287SMartin K. Petersen 
3955c6a44287SMartin K. Petersen 	switch (scsi_debug_dif) {
3956c6a44287SMartin K. Petersen 
3957c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
3958c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE1_PROTECTION;
3959c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
3960c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE1_PROTECTION;
3961c6a44287SMartin K. Petersen 		break;
3962c6a44287SMartin K. Petersen 
3963c6a44287SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
3964c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE2_PROTECTION;
3965c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
3966c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE2_PROTECTION;
3967c6a44287SMartin K. Petersen 		break;
3968c6a44287SMartin K. Petersen 
3969c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
3970c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE3_PROTECTION;
3971c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
3972c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE3_PROTECTION;
3973c6a44287SMartin K. Petersen 		break;
3974c6a44287SMartin K. Petersen 
3975c6a44287SMartin K. Petersen 	default:
3976c6a44287SMartin K. Petersen 		if (scsi_debug_dix)
3977c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE0_PROTECTION;
3978c6a44287SMartin K. Petersen 		break;
3979c6a44287SMartin K. Petersen 	}
3980c6a44287SMartin K. Petersen 
3981c6a44287SMartin K. Petersen 	scsi_host_set_prot(hpnt, host_prot);
3982c6a44287SMartin K. Petersen 
3983c6a44287SMartin K. Petersen 	printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
3984c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
3985c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
3986c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
3987c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
3988c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
3989c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
3990c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
3991c6a44287SMartin K. Petersen 
3992c6a44287SMartin K. Petersen 	if (scsi_debug_guard == 1)
3993c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
3994c6a44287SMartin K. Petersen 	else
3995c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
3996c6a44287SMartin K. Petersen 
39971da177e4SLinus Torvalds         error = scsi_add_host(hpnt, &sdbg_host->dev);
39981da177e4SLinus Torvalds         if (error) {
3999cadbd4a5SHarvey Harrison                 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
40001da177e4SLinus Torvalds                 error = -ENODEV;
40011da177e4SLinus Torvalds 		scsi_host_put(hpnt);
40021da177e4SLinus Torvalds         } else
40031da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
40041da177e4SLinus Torvalds 
40051da177e4SLinus Torvalds 
40061da177e4SLinus Torvalds         return error;
40071da177e4SLinus Torvalds }
40081da177e4SLinus Torvalds 
40091da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev)
40101da177e4SLinus Torvalds {
40111da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
40128b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
40131da177e4SLinus Torvalds 
40141da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
40151da177e4SLinus Torvalds 
40161da177e4SLinus Torvalds 	if (!sdbg_host) {
40171da177e4SLinus Torvalds 		printk(KERN_ERR "%s: Unable to locate host info\n",
4018cadbd4a5SHarvey Harrison 		       __func__);
40191da177e4SLinus Torvalds 		return -ENODEV;
40201da177e4SLinus Torvalds 	}
40211da177e4SLinus Torvalds 
40221da177e4SLinus Torvalds         scsi_remove_host(sdbg_host->shost);
40231da177e4SLinus Torvalds 
40248b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
40258b40228fSFUJITA Tomonori 				 dev_list) {
40261da177e4SLinus Torvalds                 list_del(&sdbg_devinfo->dev_list);
40271da177e4SLinus Torvalds                 kfree(sdbg_devinfo);
40281da177e4SLinus Torvalds         }
40291da177e4SLinus Torvalds 
40301da177e4SLinus Torvalds         scsi_host_put(sdbg_host->shost);
40311da177e4SLinus Torvalds         return 0;
40321da177e4SLinus Torvalds }
40331da177e4SLinus Torvalds 
40348dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
40358dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
40361da177e4SLinus Torvalds {
40378dea0d02SFUJITA Tomonori 	return 1;
40388dea0d02SFUJITA Tomonori }
40391da177e4SLinus Torvalds 
40408dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
40418dea0d02SFUJITA Tomonori 	.name = "pseudo",
40428dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
40438dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
40448dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
404582069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
40468dea0d02SFUJITA Tomonori };
4047