xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 75ad23bc)
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  *
151da177e4SLinus Torvalds  *  For documentation see http://www.torque.net/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>
331da177e4SLinus Torvalds #include <linux/types.h>
341da177e4SLinus Torvalds #include <linux/string.h>
351da177e4SLinus Torvalds #include <linux/genhd.h>
361da177e4SLinus Torvalds #include <linux/fs.h>
371da177e4SLinus Torvalds #include <linux/init.h>
381da177e4SLinus Torvalds #include <linux/proc_fs.h>
391da177e4SLinus Torvalds #include <linux/vmalloc.h>
401da177e4SLinus Torvalds #include <linux/moduleparam.h>
41852e034dSJens Axboe #include <linux/scatterlist.h>
421da177e4SLinus Torvalds #include <linux/blkdev.h>
439ff26eefSFUJITA Tomonori 
449ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
459ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
469ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
471da177e4SLinus Torvalds #include <scsi/scsi_host.h>
481da177e4SLinus Torvalds #include <scsi/scsicam.h>
49a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds #include <linux/stat.h>
521da177e4SLinus Torvalds 
531da177e4SLinus Torvalds #include "scsi_logging.h"
541da177e4SLinus Torvalds 
556f3cbf55SDouglas Gilbert #define SCSI_DEBUG_VERSION "1.81"
566f3cbf55SDouglas Gilbert static const char * scsi_debug_version_date = "20070104";
571da177e4SLinus Torvalds 
586f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
59c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
60c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
611da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
62c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
631da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
641da177e4SLinus Torvalds #define ADDR_OUT_OF_RANGE 0x21
651da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
66c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
671da177e4SLinus Torvalds #define POWERON_RESET 0x29
681da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
696f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
70c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
71c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
721da177e4SLinus Torvalds 
736f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
746f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
756f3cbf55SDouglas Gilbert 
761da177e4SLinus Torvalds #define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds /* Default values for driver parameters */
791da177e4SLinus Torvalds #define DEF_NUM_HOST   1
801da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
811da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
821da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
831da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
841da177e4SLinus Torvalds  */
851da177e4SLinus Torvalds #define DEF_DELAY   1
861da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
871da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
881da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
891da177e4SLinus Torvalds #define DEF_OPTS   0
901da177e4SLinus Torvalds #define DEF_SCSI_LEVEL   5    /* INQUIRY, byte2 [5->SPC-3] */
911da177e4SLinus Torvalds #define DEF_PTYPE   0
921da177e4SLinus Torvalds #define DEF_D_SENSE   0
93c65b1445SDouglas Gilbert #define DEF_NO_LUN_0   0
94c65b1445SDouglas Gilbert #define DEF_VIRTUAL_GB   0
9523183910SDouglas Gilbert #define DEF_FAKE_RW	0
9623183910SDouglas Gilbert #define DEF_VPD_USE_HOSTNO 1
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */
991da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE   1
1001da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR   2
1011da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT   4
1021da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR   8
1036f3cbf55SDouglas Gilbert #define SCSI_DEBUG_OPT_TRANSPORT_ERR   16
1041da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
1051da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1061da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1071da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1086f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1096f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1101da177e4SLinus Torvalds  *
1111da177e4SLinus Torvalds  * When "every_nth" < 0 then after "- every_nth" commands:
1121da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1131da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1141da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1156f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1166f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1171da177e4SLinus Torvalds  * This will continue until some other action occurs (e.g. the user
1181da177e4SLinus Torvalds  * writing a new value (other than -1 or 1) to every_nth via sysfs).
1191da177e4SLinus Torvalds  */
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
1221da177e4SLinus Torvalds  * sector on read commands: */
1231da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
1241da177e4SLinus Torvalds 
1251da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
1261da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
1271da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
128c65b1445SDouglas Gilbert #define SAM2_WLUN_REPORT_LUNS 0xc101
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST;
1311da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY;
1321da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
1331da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH;
1341da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS;
1351da177e4SLinus Torvalds static int scsi_debug_num_parts = DEF_NUM_PARTS;
1361da177e4SLinus Torvalds static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
1371da177e4SLinus Torvalds static int scsi_debug_opts = DEF_OPTS;
1381da177e4SLinus Torvalds static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
1391da177e4SLinus Torvalds static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
1401da177e4SLinus Torvalds static int scsi_debug_dsense = DEF_D_SENSE;
141c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
142c65b1445SDouglas Gilbert static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
14323183910SDouglas Gilbert static int scsi_debug_fake_rw = DEF_FAKE_RW;
14423183910SDouglas Gilbert static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds static int scsi_debug_cmnd_count = 0;
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds #define DEV_READONLY(TGT)      (0)
1491da177e4SLinus Torvalds #define DEV_REMOVEABLE(TGT)    (0)
1501da177e4SLinus Torvalds 
151c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
1521da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
1551da177e4SLinus Torvalds    may still need them */
1561da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
1571da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
1581da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds /* default sector size is 512 bytes, 2**9 bytes */
1611da177e4SLinus Torvalds #define POW2_SECT_SIZE 9
1621da177e4SLinus Torvalds #define SECT_SIZE (1 << POW2_SECT_SIZE)
1631da177e4SLinus Torvalds #define SECT_SIZE_PER(TGT) SECT_SIZE
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds #define SDEBUG_SENSE_LEN 32
1681da177e4SLinus Torvalds 
1699e603ca0SFUJITA Tomonori #define SCSI_DEBUG_CANQUEUE  255
1709e603ca0SFUJITA Tomonori #define SCSI_DEBUG_MAX_CMD_LEN 16
1719e603ca0SFUJITA Tomonori 
1721da177e4SLinus Torvalds struct sdebug_dev_info {
1731da177e4SLinus Torvalds 	struct list_head dev_list;
1741da177e4SLinus Torvalds 	unsigned char sense_buff[SDEBUG_SENSE_LEN];	/* weak nexus */
1751da177e4SLinus Torvalds 	unsigned int channel;
1761da177e4SLinus Torvalds 	unsigned int target;
1771da177e4SLinus Torvalds 	unsigned int lun;
1781da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
179c65b1445SDouglas Gilbert 	unsigned int wlun;
1801da177e4SLinus Torvalds 	char reset;
181c65b1445SDouglas Gilbert 	char stopped;
1821da177e4SLinus Torvalds 	char used;
1831da177e4SLinus Torvalds };
1841da177e4SLinus Torvalds 
1851da177e4SLinus Torvalds struct sdebug_host_info {
1861da177e4SLinus Torvalds 	struct list_head host_list;
1871da177e4SLinus Torvalds 	struct Scsi_Host *shost;
1881da177e4SLinus Torvalds 	struct device dev;
1891da177e4SLinus Torvalds 	struct list_head dev_info_list;
1901da177e4SLinus Torvalds };
1911da177e4SLinus Torvalds 
1921da177e4SLinus Torvalds #define to_sdebug_host(d)	\
1931da177e4SLinus Torvalds 	container_of(d, struct sdebug_host_info, dev)
1941da177e4SLinus Torvalds 
1951da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
1961da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
1971da177e4SLinus Torvalds 
1981da177e4SLinus Torvalds typedef void (* done_funct_t) (struct scsi_cmnd *);
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds struct sdebug_queued_cmd {
2011da177e4SLinus Torvalds 	int in_use;
2021da177e4SLinus Torvalds 	struct timer_list cmnd_timer;
2031da177e4SLinus Torvalds 	done_funct_t done_funct;
2041da177e4SLinus Torvalds 	struct scsi_cmnd * a_cmnd;
2051da177e4SLinus Torvalds 	int scsi_result;
2061da177e4SLinus Torvalds };
2071da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds static unsigned char * fake_storep;	/* ramdisk storage */
2101da177e4SLinus Torvalds 
2111da177e4SLinus Torvalds static int num_aborts = 0;
2121da177e4SLinus Torvalds static int num_dev_resets = 0;
2131da177e4SLinus Torvalds static int num_bus_resets = 0;
2141da177e4SLinus Torvalds static int num_host_resets = 0;
2151da177e4SLinus Torvalds 
2161da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock);
2171da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
2181da177e4SLinus Torvalds 
2191da177e4SLinus Torvalds static char sdebug_proc_name[] = "scsi_debug";
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
2221da177e4SLinus Torvalds 
2231da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
2241da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
2251da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
2261da177e4SLinus Torvalds };
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds static const int check_condition_result =
2291da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
2301da177e4SLinus Torvalds 
231c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
232c65b1445SDouglas Gilbert 				    0, 0, 0x2, 0x4b};
233c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
234c65b1445SDouglas Gilbert 			           0, 0, 0x0, 0x0};
235c65b1445SDouglas Gilbert 
2361da177e4SLinus Torvalds static int sdebug_add_adapter(void);
2371da177e4SLinus Torvalds static void sdebug_remove_adapter(void);
2381da177e4SLinus Torvalds 
2398dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
2408dea0d02SFUJITA Tomonori {
2418dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
2428dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
2438dea0d02SFUJITA Tomonori 
2448dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
2458dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2468dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
2478dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
2488dea0d02SFUJITA Tomonori 		    (scsi_debug_num_tgts > hpnt->this_id))
2498dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts + 1;
2508dea0d02SFUJITA Tomonori 		else
2518dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts;
2528dea0d02SFUJITA Tomonori 		/* scsi_debug_max_luns; */
2538dea0d02SFUJITA Tomonori 		hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
2548dea0d02SFUJITA Tomonori 	}
2558dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
2568dea0d02SFUJITA Tomonori }
2578dea0d02SFUJITA Tomonori 
2588dea0d02SFUJITA Tomonori static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
2598dea0d02SFUJITA Tomonori 			    int asc, int asq)
2608dea0d02SFUJITA Tomonori {
2618dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
2628dea0d02SFUJITA Tomonori 
2638dea0d02SFUJITA Tomonori 	sbuff = devip->sense_buff;
2648dea0d02SFUJITA Tomonori 	memset(sbuff, 0, SDEBUG_SENSE_LEN);
2658dea0d02SFUJITA Tomonori 
2668dea0d02SFUJITA Tomonori 	scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
2678dea0d02SFUJITA Tomonori 
2688dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2698dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug:    [sense_key,asc,ascq]: "
2708dea0d02SFUJITA Tomonori 		      "[0x%x,0x%x,0x%x]\n", key, asc, asq);
2718dea0d02SFUJITA Tomonori }
2721da177e4SLinus Torvalds 
2733de9f944SFUJITA Tomonori static void get_data_transfer_info(unsigned char *cmd,
2743de9f944SFUJITA Tomonori 				   unsigned long long *lba, unsigned int *num)
2753de9f944SFUJITA Tomonori {
2763de9f944SFUJITA Tomonori 	switch (*cmd) {
2773de9f944SFUJITA Tomonori 	case WRITE_16:
2783de9f944SFUJITA Tomonori 	case READ_16:
279d5cdc989SFUJITA Tomonori 		*lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
280d5cdc989SFUJITA Tomonori 			(u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
281d5cdc989SFUJITA Tomonori 			(u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
282d5cdc989SFUJITA Tomonori 			(u64)cmd[3] << 48 | (u64)cmd[2] << 56;
283d5cdc989SFUJITA Tomonori 
284d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
285d5cdc989SFUJITA Tomonori 			(u32)cmd[10] << 24;
2863de9f944SFUJITA Tomonori 		break;
2873de9f944SFUJITA Tomonori 	case WRITE_12:
2883de9f944SFUJITA Tomonori 	case READ_12:
289d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
290d5cdc989SFUJITA Tomonori 			(u32)cmd[2] << 24;
291d5cdc989SFUJITA Tomonori 
292d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
293d5cdc989SFUJITA Tomonori 			(u32)cmd[6] << 24;
2943de9f944SFUJITA Tomonori 		break;
2953de9f944SFUJITA Tomonori 	case WRITE_10:
2963de9f944SFUJITA Tomonori 	case READ_10:
297c639d14eSFUJITA Tomonori 	case XDWRITEREAD_10:
298d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[5] | (u32)cmd[4] << 8 |	(u32)cmd[3] << 16 |
299d5cdc989SFUJITA Tomonori 			(u32)cmd[2] << 24;
300d5cdc989SFUJITA Tomonori 
301d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[8] | (u32)cmd[7] << 8;
3023de9f944SFUJITA Tomonori 		break;
3033de9f944SFUJITA Tomonori 	case WRITE_6:
3043de9f944SFUJITA Tomonori 	case READ_6:
305d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
306d5cdc989SFUJITA Tomonori 			(u32)(cmd[1] & 0x1f) << 16;
3073de9f944SFUJITA Tomonori 		*num = (0 == cmd[4]) ? 256 : cmd[4];
3083de9f944SFUJITA Tomonori 		break;
3093de9f944SFUJITA Tomonori 	default:
3103de9f944SFUJITA Tomonori 		break;
3113de9f944SFUJITA Tomonori 	}
3123de9f944SFUJITA Tomonori }
3131da177e4SLinus Torvalds 
3141da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
3151da177e4SLinus Torvalds {
3161da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
3171da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
3181da177e4SLinus Torvalds 	}
3191da177e4SLinus Torvalds 	return -EINVAL;
3201da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
3211da177e4SLinus Torvalds }
3221da177e4SLinus Torvalds 
323c65b1445SDouglas Gilbert static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
324c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
3251da177e4SLinus Torvalds {
3261da177e4SLinus Torvalds 	if (devip->reset) {
3271da177e4SLinus Torvalds 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3281da177e4SLinus Torvalds 			printk(KERN_INFO "scsi_debug: Reporting Unit "
3291da177e4SLinus Torvalds 			       "attention: power on reset\n");
3301da177e4SLinus Torvalds 		devip->reset = 0;
3311da177e4SLinus Torvalds 		mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
3321da177e4SLinus Torvalds 		return check_condition_result;
3331da177e4SLinus Torvalds 	}
334c65b1445SDouglas Gilbert 	if ((0 == reset_only) && devip->stopped) {
335c65b1445SDouglas Gilbert 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
336c65b1445SDouglas Gilbert 			printk(KERN_INFO "scsi_debug: Reporting Not "
337c65b1445SDouglas Gilbert 			       "ready: initializing command required\n");
338c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
339c65b1445SDouglas Gilbert 				0x2);
340c65b1445SDouglas Gilbert 		return check_condition_result;
341c65b1445SDouglas Gilbert 	}
3421da177e4SLinus Torvalds 	return 0;
3431da177e4SLinus Torvalds }
3441da177e4SLinus Torvalds 
3451da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
3461da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
3471da177e4SLinus Torvalds 				int arr_len)
3481da177e4SLinus Torvalds {
34921a61829SFUJITA Tomonori 	int act_len;
350072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
3511da177e4SLinus Torvalds 
352072d0bb3SFUJITA Tomonori 	if (!sdb->length)
3531da177e4SLinus Torvalds 		return 0;
354072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
3551da177e4SLinus Torvalds 		return (DID_ERROR << 16);
35621a61829SFUJITA Tomonori 
35721a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
35821a61829SFUJITA Tomonori 				      arr, arr_len);
359072d0bb3SFUJITA Tomonori 	if (sdb->resid)
360072d0bb3SFUJITA Tomonori 		sdb->resid -= act_len;
361c65b1445SDouglas Gilbert 	else
36221a61829SFUJITA Tomonori 		sdb->resid = scsi_bufflen(scp) - act_len;
36321a61829SFUJITA Tomonori 
3641da177e4SLinus Torvalds 	return 0;
3651da177e4SLinus Torvalds }
3661da177e4SLinus Torvalds 
3671da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */
3681da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
36921a61829SFUJITA Tomonori 			       int arr_len)
3701da177e4SLinus Torvalds {
37121a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
3721da177e4SLinus Torvalds 		return 0;
373072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
3741da177e4SLinus Torvalds 		return -1;
37521a61829SFUJITA Tomonori 
37621a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
3771da177e4SLinus Torvalds }
3781da177e4SLinus Torvalds 
3791da177e4SLinus Torvalds 
3801da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux   ";
3811da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug      ";
3821da177e4SLinus Torvalds static const char * inq_product_rev = "0004";
3831da177e4SLinus Torvalds 
3845a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
3855a09e398SHannes Reinecke 			   int target_dev_id, int dev_id_num,
3865a09e398SHannes Reinecke 			   const char * dev_id_str,
387c65b1445SDouglas Gilbert 			   int dev_id_str_len)
3881da177e4SLinus Torvalds {
389c65b1445SDouglas Gilbert 	int num, port_a;
390c65b1445SDouglas Gilbert 	char b[32];
3911da177e4SLinus Torvalds 
392c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
3931da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
3941da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
3951da177e4SLinus Torvalds 	arr[1] = 0x1;
3961da177e4SLinus Torvalds 	arr[2] = 0x0;
3971da177e4SLinus Torvalds 	memcpy(&arr[4], inq_vendor_id, 8);
3981da177e4SLinus Torvalds 	memcpy(&arr[12], inq_product_id, 16);
3991da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
4001da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
4011da177e4SLinus Torvalds 	arr[3] = num;
4021da177e4SLinus Torvalds 	num += 4;
403c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
404c65b1445SDouglas Gilbert 		/* NAA-5, Logical unit identifier (binary) */
405c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* binary (not necessarily sas) */
406c65b1445SDouglas Gilbert 		arr[num++] = 0x3;	/* PIV=0, lu, naa */
407c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
408c65b1445SDouglas Gilbert 		arr[num++] = 0x8;
409c65b1445SDouglas Gilbert 		arr[num++] = 0x53;  /* naa-5 ieee company id=0x333333 (fake) */
410c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
411c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
412c65b1445SDouglas Gilbert 		arr[num++] = 0x30;
413c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 24);
414c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 16) & 0xff;
415c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 8) & 0xff;
416c65b1445SDouglas Gilbert 		arr[num++] = dev_id_num & 0xff;
417c65b1445SDouglas Gilbert 		/* Target relative port number */
418c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
419c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
420c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
421c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
422c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
423c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
424c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
425c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
426c65b1445SDouglas Gilbert 	}
427c65b1445SDouglas Gilbert 	/* NAA-5, Target port identifier */
428c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
429c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
430c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
431c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
432c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
433c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
434c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
435c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
436c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
437c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
438c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
439c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
4405a09e398SHannes Reinecke 	/* NAA-5, Target port group identifier */
4415a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
4425a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
4435a09e398SHannes Reinecke 	arr[num++] = 0x0;
4445a09e398SHannes Reinecke 	arr[num++] = 0x4;
4455a09e398SHannes Reinecke 	arr[num++] = 0;
4465a09e398SHannes Reinecke 	arr[num++] = 0;
4475a09e398SHannes Reinecke 	arr[num++] = (port_group_id >> 8) & 0xff;
4485a09e398SHannes Reinecke 	arr[num++] = port_group_id & 0xff;
449c65b1445SDouglas Gilbert 	/* NAA-5, Target device identifier */
450c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
451c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
452c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
453c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
454c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
455c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
456c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
457c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
458c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 24);
459c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 16) & 0xff;
460c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 8) & 0xff;
461c65b1445SDouglas Gilbert 	arr[num++] = target_dev_id & 0xff;
462c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
463c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
464c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
465c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
466c65b1445SDouglas Gilbert 	arr[num++] = 24;
467c65b1445SDouglas Gilbert 	memcpy(arr + num, "naa.52222220", 12);
468c65b1445SDouglas Gilbert 	num += 12;
469c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
470c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
471c65b1445SDouglas Gilbert 	num += 8;
472c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
473c65b1445SDouglas Gilbert 	num += 4;
474c65b1445SDouglas Gilbert 	return num;
475c65b1445SDouglas Gilbert }
476c65b1445SDouglas Gilbert 
477c65b1445SDouglas Gilbert 
478c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
479c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
480c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
481c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
482c65b1445SDouglas Gilbert };
483c65b1445SDouglas Gilbert 
484c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr)
485c65b1445SDouglas Gilbert {
486c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
487c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
488c65b1445SDouglas Gilbert }
489c65b1445SDouglas Gilbert 
490c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr)
491c65b1445SDouglas Gilbert {
492c65b1445SDouglas Gilbert 	int num = 0;
493c65b1445SDouglas Gilbert 	const char * na1 = "https://www.kernel.org/config";
494c65b1445SDouglas Gilbert 	const char * na2 = "http://www.kernel.org/log";
495c65b1445SDouglas Gilbert 	int plen, olen;
496c65b1445SDouglas Gilbert 
497c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
498c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
499c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
500c65b1445SDouglas Gilbert 	olen = strlen(na1);
501c65b1445SDouglas Gilbert 	plen = olen + 1;
502c65b1445SDouglas Gilbert 	if (plen % 4)
503c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
504c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
505c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
506c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
507c65b1445SDouglas Gilbert 	num += plen;
508c65b1445SDouglas Gilbert 
509c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
510c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
511c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
512c65b1445SDouglas Gilbert 	olen = strlen(na2);
513c65b1445SDouglas Gilbert 	plen = olen + 1;
514c65b1445SDouglas Gilbert 	if (plen % 4)
515c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
516c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
517c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
518c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
519c65b1445SDouglas Gilbert 	num += plen;
520c65b1445SDouglas Gilbert 
521c65b1445SDouglas Gilbert 	return num;
522c65b1445SDouglas Gilbert }
523c65b1445SDouglas Gilbert 
524c65b1445SDouglas Gilbert /* SCSI ports VPD page */
525c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
526c65b1445SDouglas Gilbert {
527c65b1445SDouglas Gilbert 	int num = 0;
528c65b1445SDouglas Gilbert 	int port_a, port_b;
529c65b1445SDouglas Gilbert 
530c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
531c65b1445SDouglas Gilbert 	port_b = port_a + 1;
532c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
533c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
534c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
535c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
536c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
537c65b1445SDouglas Gilbert 	num += 6;
538c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
539c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
540c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
541c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
542c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
543c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
544c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
545c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
546c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
547c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
548c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
549c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
550c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
551c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
552c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
553c65b1445SDouglas Gilbert 
554c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
555c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
556c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
557c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
558c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
559c65b1445SDouglas Gilbert 	num += 6;
560c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
561c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
562c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
563c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
564c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
565c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
566c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
567c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
568c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
569c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
570c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
571c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 24);
572c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 16) & 0xff;
573c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 8) & 0xff;
574c65b1445SDouglas Gilbert 	arr[num++] = port_b & 0xff;
575c65b1445SDouglas Gilbert 
576c65b1445SDouglas Gilbert 	return num;
577c65b1445SDouglas Gilbert }
578c65b1445SDouglas Gilbert 
579c65b1445SDouglas Gilbert 
580c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
581c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
582c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
583c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
584c65b1445SDouglas Gilbert '1','2','3','4',
585c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
586c65b1445SDouglas Gilbert 0xec,0,0,0,
587c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
588c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
589c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
590c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
591c65b1445SDouglas Gilbert 0x53,0x41,
592c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
593c65b1445SDouglas Gilbert 0x20,0x20,
594c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
595c65b1445SDouglas Gilbert 0x10,0x80,
596c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
597c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
598c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
599c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
600c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
601c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
602c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
603c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
604c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
605c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
606c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
607c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
608c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
609c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
610c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
611c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
612c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
613c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
614c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
615c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
616c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
617c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
618c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
619c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
620c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
621c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
622c65b1445SDouglas Gilbert };
623c65b1445SDouglas Gilbert 
624c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr)
625c65b1445SDouglas Gilbert {
626c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
627c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
628c65b1445SDouglas Gilbert }
629c65b1445SDouglas Gilbert 
630c65b1445SDouglas Gilbert 
631c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
632c65b1445SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4,
633c65b1445SDouglas Gilbert 	0,0,0x4,0,
634c65b1445SDouglas Gilbert 	0,0,0,64,
635c65b1445SDouglas Gilbert };
636c65b1445SDouglas Gilbert 
637c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr)
638c65b1445SDouglas Gilbert {
639c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
640c65b1445SDouglas Gilbert 	if (sdebug_store_sectors > 0x400) {
641c65b1445SDouglas Gilbert 		arr[4] = (sdebug_store_sectors >> 24) & 0xff;
642c65b1445SDouglas Gilbert 		arr[5] = (sdebug_store_sectors >> 16) & 0xff;
643c65b1445SDouglas Gilbert 		arr[6] = (sdebug_store_sectors >> 8) & 0xff;
644c65b1445SDouglas Gilbert 		arr[7] = sdebug_store_sectors & 0xff;
645c65b1445SDouglas Gilbert 	}
646c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
6471da177e4SLinus Torvalds }
6481da177e4SLinus Torvalds 
6491da177e4SLinus Torvalds 
6501da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
651c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
6521da177e4SLinus Torvalds 
6531da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd * scp, int target,
6541da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
6551da177e4SLinus Torvalds {
6561da177e4SLinus Torvalds 	unsigned char pq_pdt;
6575a09e398SHannes Reinecke 	unsigned char * arr;
6581da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
6595a09e398SHannes Reinecke 	int alloc_len, n, ret;
6601da177e4SLinus Torvalds 
6611da177e4SLinus Torvalds 	alloc_len = (cmd[3] << 8) + cmd[4];
6626f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
6636f3cbf55SDouglas Gilbert 	if (! arr)
6646f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
665c65b1445SDouglas Gilbert 	if (devip->wlun)
666c65b1445SDouglas Gilbert 		pq_pdt = 0x1e;	/* present, wlun */
667c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (0 == devip->lun))
668c65b1445SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, no device type */
669c65b1445SDouglas Gilbert 	else
6701da177e4SLinus Torvalds 		pq_pdt = (scsi_debug_ptype & 0x1f);
6711da177e4SLinus Torvalds 	arr[0] = pq_pdt;
6721da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
6731da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
6741da177e4SLinus Torvalds 			       	0);
6755a09e398SHannes Reinecke 		kfree(arr);
6761da177e4SLinus Torvalds 		return check_condition_result;
6771da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
6785a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
679c65b1445SDouglas Gilbert 		char lu_id_str[6];
680c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
6811da177e4SLinus Torvalds 
6825a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
6835a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
68423183910SDouglas Gilbert 		if (0 == scsi_debug_vpd_use_hostno)
68523183910SDouglas Gilbert 			host_no = 0;
686c65b1445SDouglas Gilbert 		lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
687c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
688c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
689c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
690c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
6911da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
692c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
693c65b1445SDouglas Gilbert 			n = 4;
694c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
695c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
696c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
697c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
698c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
699c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
700c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
701c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
702c65b1445SDouglas Gilbert 			arr[n++] = 0x89;  /* ATA information */
703c65b1445SDouglas Gilbert 			arr[n++] = 0xb0;  /* Block limits (SBC) */
704c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
7051da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
706c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
7071da177e4SLinus Torvalds 			arr[3] = len;
708c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
7091da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
710c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
7115a09e398SHannes Reinecke 			arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
7125a09e398SHannes Reinecke 						 target_dev_id, lu_id_num,
7135a09e398SHannes Reinecke 						 lu_id_str, len);
714c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
715c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
716c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_84(&arr[4]);
717c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
718c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
719c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_85(&arr[4]);
720c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
721c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
722c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
723c65b1445SDouglas Gilbert 			arr[4] = 0x0;   /* no protection stuff */
724c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
725c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
726c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
727c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
728c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
729c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
730c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
731c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
732c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
733c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
734c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
735c65b1445SDouglas Gilbert 		} else if (0x89 == cmd[2]) { /* ATA information */
736c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
737c65b1445SDouglas Gilbert 			n = inquiry_evpd_89(&arr[4]);
738c65b1445SDouglas Gilbert 			arr[2] = (n >> 8);
739c65b1445SDouglas Gilbert 			arr[3] = (n & 0xff);
740c65b1445SDouglas Gilbert 		} else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
741c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
742c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_b0(&arr[4]);
7431da177e4SLinus Torvalds 		} else {
7441da177e4SLinus Torvalds 			/* Illegal request, invalid field in cdb */
7451da177e4SLinus Torvalds 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
7461da177e4SLinus Torvalds 					INVALID_FIELD_IN_CDB, 0);
7475a09e398SHannes Reinecke 			kfree(arr);
7481da177e4SLinus Torvalds 			return check_condition_result;
7491da177e4SLinus Torvalds 		}
750c65b1445SDouglas Gilbert 		len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
7515a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
752c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
7535a09e398SHannes Reinecke 		kfree(arr);
7545a09e398SHannes Reinecke 		return ret;
7551da177e4SLinus Torvalds 	}
7561da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
7571da177e4SLinus Torvalds 	arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0;	/* Removable disk */
7581da177e4SLinus Torvalds 	arr[2] = scsi_debug_scsi_level;
7591da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
7601da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
7615a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno)
7625a09e398SHannes Reinecke 		arr[5] = 0x10; /* claim: implicit TGPS */
763c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
7641da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
765c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
7661da177e4SLinus Torvalds 	memcpy(&arr[8], inq_vendor_id, 8);
7671da177e4SLinus Torvalds 	memcpy(&arr[16], inq_product_id, 16);
7681da177e4SLinus Torvalds 	memcpy(&arr[32], inq_product_rev, 4);
7691da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
770c65b1445SDouglas Gilbert 	arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
771c65b1445SDouglas Gilbert 	arr[60] = 0x3; arr[61] = 0x14;  /* SPC-3 ANSI */
772c65b1445SDouglas Gilbert 	n = 62;
7731da177e4SLinus Torvalds 	if (scsi_debug_ptype == 0) {
774c65b1445SDouglas Gilbert 		arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
7751da177e4SLinus Torvalds 	} else if (scsi_debug_ptype == 1) {
776c65b1445SDouglas Gilbert 		arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
7771da177e4SLinus Torvalds 	}
778c65b1445SDouglas Gilbert 	arr[n++] = 0xc; arr[n++] = 0xf;  /* SAS-1.1 rev 10 */
7795a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
7801da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
7815a09e398SHannes Reinecke 	kfree(arr);
7825a09e398SHannes Reinecke 	return ret;
7831da177e4SLinus Torvalds }
7841da177e4SLinus Torvalds 
7851da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp,
7861da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip)
7871da177e4SLinus Torvalds {
7881da177e4SLinus Torvalds 	unsigned char * sbuff;
7891da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
7901da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_SENSE_LEN];
791c65b1445SDouglas Gilbert 	int want_dsense;
7921da177e4SLinus Torvalds 	int len = 18;
7931da177e4SLinus Torvalds 
794c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
7951da177e4SLinus Torvalds 	if (devip->reset == 1)
796c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
797c65b1445SDouglas Gilbert 	want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
7981da177e4SLinus Torvalds 	sbuff = devip->sense_buff;
799c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
800c65b1445SDouglas Gilbert 		if (want_dsense) {
801c65b1445SDouglas Gilbert 			arr[0] = 0x72;
802c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
803c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
804c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
805c65b1445SDouglas Gilbert 		} else {
806c65b1445SDouglas Gilbert 			arr[0] = 0x70;
807c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
808c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
809c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
810c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
811c65b1445SDouglas Gilbert 		}
812c65b1445SDouglas Gilbert 	} else {
813c65b1445SDouglas Gilbert 		memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
8141da177e4SLinus Torvalds 		if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
8151da177e4SLinus Torvalds 			/* DESC bit set and sense_buff in fixed format */
816c65b1445SDouglas Gilbert 			memset(arr, 0, sizeof(arr));
8171da177e4SLinus Torvalds 			arr[0] = 0x72;
8181da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
8191da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
8201da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
8211da177e4SLinus Torvalds 			len = 8;
822c65b1445SDouglas Gilbert 		}
823c65b1445SDouglas Gilbert 	}
824c65b1445SDouglas Gilbert 	mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
8251da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
8261da177e4SLinus Torvalds }
8271da177e4SLinus Torvalds 
828c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp,
829c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
830c65b1445SDouglas Gilbert {
831c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
832c65b1445SDouglas Gilbert 	int power_cond, errsts, start;
833c65b1445SDouglas Gilbert 
834c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
835c65b1445SDouglas Gilbert 		return errsts;
836c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
837c65b1445SDouglas Gilbert 	if (power_cond) {
838c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
839c65b1445SDouglas Gilbert 			       	0);
840c65b1445SDouglas Gilbert 		return check_condition_result;
841c65b1445SDouglas Gilbert 	}
842c65b1445SDouglas Gilbert 	start = cmd[4] & 1;
843c65b1445SDouglas Gilbert 	if (start == devip->stopped)
844c65b1445SDouglas Gilbert 		devip->stopped = !start;
845c65b1445SDouglas Gilbert 	return 0;
846c65b1445SDouglas Gilbert }
847c65b1445SDouglas Gilbert 
84828898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
84928898873SFUJITA Tomonori {
85028898873SFUJITA Tomonori 	if (scsi_debug_virtual_gb > 0)
85128898873SFUJITA Tomonori 		return 2048 * 1024 * scsi_debug_virtual_gb;
85228898873SFUJITA Tomonori 	else
85328898873SFUJITA Tomonori 		return sdebug_store_sectors;
85428898873SFUJITA Tomonori }
85528898873SFUJITA Tomonori 
8561da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
8571da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp,
8581da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
8591da177e4SLinus Torvalds {
8601da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
861c65b1445SDouglas Gilbert 	unsigned int capac;
8621da177e4SLinus Torvalds 	int errsts;
8631da177e4SLinus Torvalds 
864c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
8651da177e4SLinus Torvalds 		return errsts;
866c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
86728898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
8681da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
869c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
870c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
8711da177e4SLinus Torvalds 		arr[0] = (capac >> 24);
8721da177e4SLinus Torvalds 		arr[1] = (capac >> 16) & 0xff;
8731da177e4SLinus Torvalds 		arr[2] = (capac >> 8) & 0xff;
8741da177e4SLinus Torvalds 		arr[3] = capac & 0xff;
875c65b1445SDouglas Gilbert 	} else {
876c65b1445SDouglas Gilbert 		arr[0] = 0xff;
877c65b1445SDouglas Gilbert 		arr[1] = 0xff;
878c65b1445SDouglas Gilbert 		arr[2] = 0xff;
879c65b1445SDouglas Gilbert 		arr[3] = 0xff;
880c65b1445SDouglas Gilbert 	}
8811da177e4SLinus Torvalds 	arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
8821da177e4SLinus Torvalds 	arr[7] = SECT_SIZE_PER(target) & 0xff;
8831da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
8841da177e4SLinus Torvalds }
8851da177e4SLinus Torvalds 
886c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
887c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp,
888c65b1445SDouglas Gilbert 			  struct sdebug_dev_info * devip)
889c65b1445SDouglas Gilbert {
890c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
891c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
892c65b1445SDouglas Gilbert 	unsigned long long capac;
893c65b1445SDouglas Gilbert 	int errsts, k, alloc_len;
894c65b1445SDouglas Gilbert 
895c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
896c65b1445SDouglas Gilbert 		return errsts;
897c65b1445SDouglas Gilbert 	alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
898c65b1445SDouglas Gilbert 		     + cmd[13]);
899c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
90028898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
901c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
902c65b1445SDouglas Gilbert 	capac = sdebug_capacity - 1;
903c65b1445SDouglas Gilbert 	for (k = 0; k < 8; ++k, capac >>= 8)
904c65b1445SDouglas Gilbert 		arr[7 - k] = capac & 0xff;
905c65b1445SDouglas Gilbert 	arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
906c65b1445SDouglas Gilbert 	arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
907c65b1445SDouglas Gilbert 	arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
908c65b1445SDouglas Gilbert 	arr[11] = SECT_SIZE_PER(target) & 0xff;
909c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
910c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
911c65b1445SDouglas Gilbert }
912c65b1445SDouglas Gilbert 
9135a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
9145a09e398SHannes Reinecke 
9155a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp,
9165a09e398SHannes Reinecke 			      struct sdebug_dev_info * devip)
9175a09e398SHannes Reinecke {
9185a09e398SHannes Reinecke 	unsigned char *cmd = (unsigned char *)scp->cmnd;
9195a09e398SHannes Reinecke 	unsigned char * arr;
9205a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
9215a09e398SHannes Reinecke 	int n, ret, alen, rlen;
9225a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
9235a09e398SHannes Reinecke 
9245a09e398SHannes Reinecke 	alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
9255a09e398SHannes Reinecke 		+ cmd[9]);
9265a09e398SHannes Reinecke 
9276f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
9286f3cbf55SDouglas Gilbert 	if (! arr)
9296f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
9305a09e398SHannes Reinecke 	/*
9315a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
9325a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
9335a09e398SHannes Reinecke 	 * So we create two port groups with one port each
9345a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
9355a09e398SHannes Reinecke 	 */
9365a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
9375a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
9385a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
9395a09e398SHannes Reinecke 	    (devip->channel & 0x7f);
9405a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
9415a09e398SHannes Reinecke 	    (devip->channel & 0x7f) + 0x80;
9425a09e398SHannes Reinecke 
9435a09e398SHannes Reinecke 	/*
9445a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
9455a09e398SHannes Reinecke 	 */
9465a09e398SHannes Reinecke 	n = 4;
9475a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno) {
9485a09e398SHannes Reinecke 	    arr[n++] = host_no % 3; /* Asymm access state */
9495a09e398SHannes Reinecke 	    arr[n++] = 0x0F; /* claim: all states are supported */
9505a09e398SHannes Reinecke 	} else {
9515a09e398SHannes Reinecke 	    arr[n++] = 0x0; /* Active/Optimized path */
9525a09e398SHannes Reinecke 	    arr[n++] = 0x01; /* claim: only support active/optimized paths */
9535a09e398SHannes Reinecke 	}
9545a09e398SHannes Reinecke 	arr[n++] = (port_group_a >> 8) & 0xff;
9555a09e398SHannes Reinecke 	arr[n++] = port_group_a & 0xff;
9565a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
9575a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
9585a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
9595a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
9605a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
9615a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
9625a09e398SHannes Reinecke 	arr[n++] = (port_a >> 8) & 0xff;
9635a09e398SHannes Reinecke 	arr[n++] = port_a & 0xff;
9645a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
9655a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
9665a09e398SHannes Reinecke 	arr[n++] = (port_group_b >> 8) & 0xff;
9675a09e398SHannes Reinecke 	arr[n++] = port_group_b & 0xff;
9685a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
9695a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
9705a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
9715a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
9725a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
9735a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
9745a09e398SHannes Reinecke 	arr[n++] = (port_b >> 8) & 0xff;
9755a09e398SHannes Reinecke 	arr[n++] = port_b & 0xff;
9765a09e398SHannes Reinecke 
9775a09e398SHannes Reinecke 	rlen = n - 4;
9785a09e398SHannes Reinecke 	arr[0] = (rlen >> 24) & 0xff;
9795a09e398SHannes Reinecke 	arr[1] = (rlen >> 16) & 0xff;
9805a09e398SHannes Reinecke 	arr[2] = (rlen >> 8) & 0xff;
9815a09e398SHannes Reinecke 	arr[3] = rlen & 0xff;
9825a09e398SHannes Reinecke 
9835a09e398SHannes Reinecke 	/*
9845a09e398SHannes Reinecke 	 * Return the smallest value of either
9855a09e398SHannes Reinecke 	 * - The allocated length
9865a09e398SHannes Reinecke 	 * - The constructed command length
9875a09e398SHannes Reinecke 	 * - The maximum array size
9885a09e398SHannes Reinecke 	 */
9895a09e398SHannes Reinecke 	rlen = min(alen,n);
9905a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
9915a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
9925a09e398SHannes Reinecke 	kfree(arr);
9935a09e398SHannes Reinecke 	return ret;
9945a09e398SHannes Reinecke }
9955a09e398SHannes Reinecke 
9961da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
9971da177e4SLinus Torvalds 
9981da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
9991da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
10001da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
10011da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
10021da177e4SLinus Torvalds 
10031da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
10041da177e4SLinus Torvalds 	if (1 == pcontrol)
10051da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
10061da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
10071da177e4SLinus Torvalds }
10081da177e4SLinus Torvalds 
10091da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
10101da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
10111da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
10121da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
10131da177e4SLinus Torvalds 
10141da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
10151da177e4SLinus Torvalds 	if (1 == pcontrol)
10161da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
10171da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
10181da177e4SLinus Torvalds }
10191da177e4SLinus Torvalds 
10201da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target)
10211da177e4SLinus Torvalds {       /* Format device page for mode_sense */
10221da177e4SLinus Torvalds         unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
10231da177e4SLinus Torvalds                                      0, 0, 0, 0, 0, 0, 0, 0,
10241da177e4SLinus Torvalds                                      0, 0, 0, 0, 0x40, 0, 0, 0};
10251da177e4SLinus Torvalds 
10261da177e4SLinus Torvalds         memcpy(p, format_pg, sizeof(format_pg));
10271da177e4SLinus Torvalds         p[10] = (sdebug_sectors_per >> 8) & 0xff;
10281da177e4SLinus Torvalds         p[11] = sdebug_sectors_per & 0xff;
10291da177e4SLinus Torvalds         p[12] = (SECT_SIZE >> 8) & 0xff;
10301da177e4SLinus Torvalds         p[13] = SECT_SIZE & 0xff;
10311da177e4SLinus Torvalds         if (DEV_REMOVEABLE(target))
10321da177e4SLinus Torvalds                 p[20] |= 0x20; /* should agree with INQUIRY */
10331da177e4SLinus Torvalds         if (1 == pcontrol)
10341da177e4SLinus Torvalds                 memset(p + 2, 0, sizeof(format_pg) - 2);
10351da177e4SLinus Torvalds         return sizeof(format_pg);
10361da177e4SLinus Torvalds }
10371da177e4SLinus Torvalds 
10381da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
10391da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
10401da177e4SLinus Torvalds 	unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
10411da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
10421da177e4SLinus Torvalds 
10431da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
10441da177e4SLinus Torvalds 	if (1 == pcontrol)
10451da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(caching_pg) - 2);
10461da177e4SLinus Torvalds 	return sizeof(caching_pg);
10471da177e4SLinus Torvalds }
10481da177e4SLinus Torvalds 
10491da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
10501da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
1051c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1052c65b1445SDouglas Gilbert 				        0, 0, 0, 0};
1053c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
10541da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
10551da177e4SLinus Torvalds 
10561da177e4SLinus Torvalds 	if (scsi_debug_dsense)
10571da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
1058c65b1445SDouglas Gilbert 	else
1059c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
10601da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
10611da177e4SLinus Torvalds 	if (1 == pcontrol)
1062c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1063c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1064c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
10651da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
10661da177e4SLinus Torvalds }
10671da177e4SLinus Torvalds 
1068c65b1445SDouglas Gilbert 
10691da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
10701da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
1071c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
10721da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
1073c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1074c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
1075c65b1445SDouglas Gilbert 
10761da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
10771da177e4SLinus Torvalds 	if (1 == pcontrol)
1078c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1079c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1080c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
10811da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
10821da177e4SLinus Torvalds }
10831da177e4SLinus Torvalds 
1084c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1085c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
1086c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1087c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1088c65b1445SDouglas Gilbert 
1089c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1090c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1091c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1092c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
1093c65b1445SDouglas Gilbert }
1094c65b1445SDouglas Gilbert 
1095c65b1445SDouglas Gilbert 
1096c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1097c65b1445SDouglas Gilbert 			      int target_dev_id)
1098c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
1099c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1100c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1101c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1102c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1103c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
1104c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1105c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1106c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1107c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1108c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1109c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
1110c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1111c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1112c65b1445SDouglas Gilbert 		};
1113c65b1445SDouglas Gilbert 	int port_a, port_b;
1114c65b1445SDouglas Gilbert 
1115c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1116c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1117c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1118c65b1445SDouglas Gilbert 	p[20] = (port_a >> 24);
1119c65b1445SDouglas Gilbert 	p[21] = (port_a >> 16) & 0xff;
1120c65b1445SDouglas Gilbert 	p[22] = (port_a >> 8) & 0xff;
1121c65b1445SDouglas Gilbert 	p[23] = port_a & 0xff;
1122c65b1445SDouglas Gilbert 	p[48 + 20] = (port_b >> 24);
1123c65b1445SDouglas Gilbert 	p[48 + 21] = (port_b >> 16) & 0xff;
1124c65b1445SDouglas Gilbert 	p[48 + 22] = (port_b >> 8) & 0xff;
1125c65b1445SDouglas Gilbert 	p[48 + 23] = port_b & 0xff;
1126c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1127c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1128c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
1129c65b1445SDouglas Gilbert }
1130c65b1445SDouglas Gilbert 
1131c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1132c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
1133c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1134c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1135c65b1445SDouglas Gilbert 		};
1136c65b1445SDouglas Gilbert 
1137c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1138c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1139c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1140c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
1141c65b1445SDouglas Gilbert }
1142c65b1445SDouglas Gilbert 
11431da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
11441da177e4SLinus Torvalds 
11451da177e4SLinus Torvalds static int resp_mode_sense(struct scsi_cmnd * scp, int target,
11461da177e4SLinus Torvalds 			   struct sdebug_dev_info * devip)
11471da177e4SLinus Torvalds {
114823183910SDouglas Gilbert 	unsigned char dbd, llbaa;
114923183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
11501da177e4SLinus Torvalds 	unsigned char dev_spec;
115123183910SDouglas Gilbert 	int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
11521da177e4SLinus Torvalds 	unsigned char * ap;
11531da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
11541da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
11551da177e4SLinus Torvalds 
1156c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
11571da177e4SLinus Torvalds 		return errsts;
115823183910SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);
11591da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
11601da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
11611da177e4SLinus Torvalds 	subpcode = cmd[3];
11621da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
116323183910SDouglas Gilbert 	llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
116423183910SDouglas Gilbert 	if ((0 == scsi_debug_ptype) && (0 == dbd))
116523183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
116623183910SDouglas Gilbert 	else
116723183910SDouglas Gilbert 		bd_len = 0;
11681da177e4SLinus Torvalds 	alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
11691da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
11701da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
11711da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
11721da177e4SLinus Torvalds 			       	0);
11731da177e4SLinus Torvalds 		return check_condition_result;
11741da177e4SLinus Torvalds 	}
1175c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1176c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
117723183910SDouglas Gilbert 	/* set DPOFUA bit for disks */
117823183910SDouglas Gilbert 	if (0 == scsi_debug_ptype)
117923183910SDouglas Gilbert 		dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
118023183910SDouglas Gilbert 	else
118123183910SDouglas Gilbert 		dev_spec = 0x0;
11821da177e4SLinus Torvalds 	if (msense_6) {
11831da177e4SLinus Torvalds 		arr[2] = dev_spec;
118423183910SDouglas Gilbert 		arr[3] = bd_len;
11851da177e4SLinus Torvalds 		offset = 4;
11861da177e4SLinus Torvalds 	} else {
11871da177e4SLinus Torvalds 		arr[3] = dev_spec;
118823183910SDouglas Gilbert 		if (16 == bd_len)
118923183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
119023183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
11911da177e4SLinus Torvalds 		offset = 8;
11921da177e4SLinus Torvalds 	}
11931da177e4SLinus Torvalds 	ap = arr + offset;
119428898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
119528898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
119628898873SFUJITA Tomonori 
119723183910SDouglas Gilbert 	if (8 == bd_len) {
119823183910SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe) {
119923183910SDouglas Gilbert 			ap[0] = 0xff;
120023183910SDouglas Gilbert 			ap[1] = 0xff;
120123183910SDouglas Gilbert 			ap[2] = 0xff;
120223183910SDouglas Gilbert 			ap[3] = 0xff;
120323183910SDouglas Gilbert 		} else {
120423183910SDouglas Gilbert 			ap[0] = (sdebug_capacity >> 24) & 0xff;
120523183910SDouglas Gilbert 			ap[1] = (sdebug_capacity >> 16) & 0xff;
120623183910SDouglas Gilbert 			ap[2] = (sdebug_capacity >> 8) & 0xff;
120723183910SDouglas Gilbert 			ap[3] = sdebug_capacity & 0xff;
120823183910SDouglas Gilbert 		}
120923183910SDouglas Gilbert         	ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
121023183910SDouglas Gilbert         	ap[7] = SECT_SIZE_PER(target) & 0xff;
121123183910SDouglas Gilbert 		offset += bd_len;
121223183910SDouglas Gilbert 		ap = arr + offset;
121323183910SDouglas Gilbert 	} else if (16 == bd_len) {
121423183910SDouglas Gilbert 		unsigned long long capac = sdebug_capacity;
121523183910SDouglas Gilbert 
121623183910SDouglas Gilbert         	for (k = 0; k < 8; ++k, capac >>= 8)
121723183910SDouglas Gilbert                 	ap[7 - k] = capac & 0xff;
121823183910SDouglas Gilbert         	ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
121923183910SDouglas Gilbert         	ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
122023183910SDouglas Gilbert         	ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
122123183910SDouglas Gilbert         	ap[15] = SECT_SIZE_PER(target) & 0xff;
122223183910SDouglas Gilbert 		offset += bd_len;
122323183910SDouglas Gilbert 		ap = arr + offset;
122423183910SDouglas Gilbert 	}
12251da177e4SLinus Torvalds 
1226c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1227c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
12281da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
12291da177e4SLinus Torvalds 			       	0);
12301da177e4SLinus Torvalds 		return check_condition_result;
12311da177e4SLinus Torvalds 	}
12321da177e4SLinus Torvalds 	switch (pcode) {
12331da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
12341da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
12351da177e4SLinus Torvalds 		offset += len;
12361da177e4SLinus Torvalds 		break;
12371da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
12381da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
12391da177e4SLinus Torvalds 		offset += len;
12401da177e4SLinus Torvalds 		break;
12411da177e4SLinus Torvalds         case 0x3:       /* Format device page, direct access */
12421da177e4SLinus Torvalds                 len = resp_format_pg(ap, pcontrol, target);
12431da177e4SLinus Torvalds                 offset += len;
12441da177e4SLinus Torvalds                 break;
12451da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
12461da177e4SLinus Torvalds 		len = resp_caching_pg(ap, pcontrol, target);
12471da177e4SLinus Torvalds 		offset += len;
12481da177e4SLinus Torvalds 		break;
12491da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
12501da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
12511da177e4SLinus Torvalds 		offset += len;
12521da177e4SLinus Torvalds 		break;
1253c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
1254c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
1255c65b1445SDouglas Gilbert 		        mk_sense_buffer(devip, ILLEGAL_REQUEST,
1256c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1257c65b1445SDouglas Gilbert 			return check_condition_result;
1258c65b1445SDouglas Gilbert 	        }
1259c65b1445SDouglas Gilbert 		len = 0;
1260c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
1261c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1262c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
1263c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1264c65b1445SDouglas Gilbert 						  target_dev_id);
1265c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
1266c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
1267c65b1445SDouglas Gilbert 		offset += len;
1268c65b1445SDouglas Gilbert 		break;
12691da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
12701da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
12711da177e4SLinus Torvalds 		offset += len;
12721da177e4SLinus Torvalds 		break;
12731da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
1274c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
12751da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
12761da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
12771da177e4SLinus Torvalds 			len += resp_format_pg(ap + len, pcontrol, target);
12781da177e4SLinus Torvalds 			len += resp_caching_pg(ap + len, pcontrol, target);
12791da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1280c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1281c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
1282c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1283c65b1445SDouglas Gilbert 						  target, target_dev_id);
1284c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
1285c65b1445SDouglas Gilbert 			}
12861da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
1287c65b1445SDouglas Gilbert 		} else {
1288c65b1445SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
1289c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1290c65b1445SDouglas Gilbert 			return check_condition_result;
1291c65b1445SDouglas Gilbert                 }
12921da177e4SLinus Torvalds 		offset += len;
12931da177e4SLinus Torvalds 		break;
12941da177e4SLinus Torvalds 	default:
12951da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
12961da177e4SLinus Torvalds 			       	0);
12971da177e4SLinus Torvalds 		return check_condition_result;
12981da177e4SLinus Torvalds 	}
12991da177e4SLinus Torvalds 	if (msense_6)
13001da177e4SLinus Torvalds 		arr[0] = offset - 1;
13011da177e4SLinus Torvalds 	else {
13021da177e4SLinus Torvalds 		arr[0] = ((offset - 2) >> 8) & 0xff;
13031da177e4SLinus Torvalds 		arr[1] = (offset - 2) & 0xff;
13041da177e4SLinus Torvalds 	}
13051da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
13061da177e4SLinus Torvalds }
13071da177e4SLinus Torvalds 
1308c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
1309c65b1445SDouglas Gilbert 
1310c65b1445SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1311c65b1445SDouglas Gilbert 			    struct sdebug_dev_info * devip)
1312c65b1445SDouglas Gilbert {
1313c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1314c65b1445SDouglas Gilbert 	int param_len, res, errsts, mpage;
1315c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1316c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1317c65b1445SDouglas Gilbert 
1318c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1319c65b1445SDouglas Gilbert 		return errsts;
1320c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1321c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
1322c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
1323c65b1445SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1324c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1325c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1326c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
1327c65b1445SDouglas Gilbert 		return check_condition_result;
1328c65b1445SDouglas Gilbert 	}
1329c65b1445SDouglas Gilbert         res = fetch_to_dev_buffer(scp, arr, param_len);
1330c65b1445SDouglas Gilbert         if (-1 == res)
1331c65b1445SDouglas Gilbert                 return (DID_ERROR << 16);
1332c65b1445SDouglas Gilbert         else if ((res < param_len) &&
1333c65b1445SDouglas Gilbert                  (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1334c65b1445SDouglas Gilbert                 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1335c65b1445SDouglas Gilbert                        " IO sent=%d bytes\n", param_len, res);
1336c65b1445SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1337c65b1445SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
133823183910SDouglas Gilbert 	if (md_len > 2) {
1339c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1340c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_PARAM_LIST, 0);
1341c65b1445SDouglas Gilbert 		return check_condition_result;
1342c65b1445SDouglas Gilbert 	}
1343c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
1344c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
1345c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
1346c65b1445SDouglas Gilbert 	if (ps) {
1347c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1348c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_PARAM_LIST, 0);
1349c65b1445SDouglas Gilbert 		return check_condition_result;
1350c65b1445SDouglas Gilbert 	}
1351c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
1352c65b1445SDouglas Gilbert 	pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1353c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
1354c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
1355c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1356c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
1357c65b1445SDouglas Gilbert 		return check_condition_result;
1358c65b1445SDouglas Gilbert 	}
1359c65b1445SDouglas Gilbert 	switch (mpage) {
1360c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
1361c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
1362c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
1363c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
1364c65b1445SDouglas Gilbert 			scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1365c65b1445SDouglas Gilbert 			return 0;
1366c65b1445SDouglas Gilbert 		}
1367c65b1445SDouglas Gilbert 		break;
1368c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
1369c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
1370c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
1371c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
1372c65b1445SDouglas Gilbert 			return 0;
1373c65b1445SDouglas Gilbert 		}
1374c65b1445SDouglas Gilbert 		break;
1375c65b1445SDouglas Gilbert 	default:
1376c65b1445SDouglas Gilbert 		break;
1377c65b1445SDouglas Gilbert 	}
1378c65b1445SDouglas Gilbert 	mk_sense_buffer(devip, ILLEGAL_REQUEST,
1379c65b1445SDouglas Gilbert 			INVALID_FIELD_IN_PARAM_LIST, 0);
1380c65b1445SDouglas Gilbert 	return check_condition_result;
1381c65b1445SDouglas Gilbert }
1382c65b1445SDouglas Gilbert 
1383c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr)
1384c65b1445SDouglas Gilbert {
1385c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1386c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
1387c65b1445SDouglas Gilbert 		};
1388c65b1445SDouglas Gilbert 
1389c65b1445SDouglas Gilbert         memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1390c65b1445SDouglas Gilbert         return sizeof(temp_l_pg);
1391c65b1445SDouglas Gilbert }
1392c65b1445SDouglas Gilbert 
1393c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr)
1394c65b1445SDouglas Gilbert {
1395c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1396c65b1445SDouglas Gilbert 		};
1397c65b1445SDouglas Gilbert 
1398c65b1445SDouglas Gilbert         memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1399c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
1400c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
1401c65b1445SDouglas Gilbert 		arr[5] = 0xff;
1402c65b1445SDouglas Gilbert 	}
1403c65b1445SDouglas Gilbert         return sizeof(ie_l_pg);
1404c65b1445SDouglas Gilbert }
1405c65b1445SDouglas Gilbert 
1406c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
1407c65b1445SDouglas Gilbert 
1408c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp,
1409c65b1445SDouglas Gilbert                           struct sdebug_dev_info * devip)
1410c65b1445SDouglas Gilbert {
141123183910SDouglas Gilbert 	int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
1412c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1413c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1414c65b1445SDouglas Gilbert 
1415c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1416c65b1445SDouglas Gilbert 		return errsts;
1417c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1418c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
1419c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
1420c65b1445SDouglas Gilbert 	if (ppc || sp) {
1421c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1422c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
1423c65b1445SDouglas Gilbert 		return check_condition_result;
1424c65b1445SDouglas Gilbert 	}
1425c65b1445SDouglas Gilbert 	pcontrol = (cmd[2] & 0xc0) >> 6;
1426c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
142723183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
1428c65b1445SDouglas Gilbert 	alloc_len = (cmd[7] << 8) + cmd[8];
1429c65b1445SDouglas Gilbert 	arr[0] = pcode;
143023183910SDouglas Gilbert 	if (0 == subpcode) {
1431c65b1445SDouglas Gilbert 		switch (pcode) {
1432c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
1433c65b1445SDouglas Gilbert 			n = 4;
1434c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
1435c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
1436c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
1437c65b1445SDouglas Gilbert 			arr[3] = n - 4;
1438c65b1445SDouglas Gilbert 			break;
1439c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
1440c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
1441c65b1445SDouglas Gilbert 			break;
1442c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
1443c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
1444c65b1445SDouglas Gilbert 			break;
1445c65b1445SDouglas Gilbert 		default:
1446c65b1445SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
1447c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1448c65b1445SDouglas Gilbert 			return check_condition_result;
1449c65b1445SDouglas Gilbert 		}
145023183910SDouglas Gilbert 	} else if (0xff == subpcode) {
145123183910SDouglas Gilbert 		arr[0] |= 0x40;
145223183910SDouglas Gilbert 		arr[1] = subpcode;
145323183910SDouglas Gilbert 		switch (pcode) {
145423183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
145523183910SDouglas Gilbert 			n = 4;
145623183910SDouglas Gilbert 			arr[n++] = 0x0;
145723183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
145823183910SDouglas Gilbert 			arr[n++] = 0x0;
145923183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
146023183910SDouglas Gilbert 			arr[n++] = 0xd;
146123183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
146223183910SDouglas Gilbert 			arr[n++] = 0x2f;
146323183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
146423183910SDouglas Gilbert 			arr[3] = n - 4;
146523183910SDouglas Gilbert 			break;
146623183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
146723183910SDouglas Gilbert 			n = 4;
146823183910SDouglas Gilbert 			arr[n++] = 0xd;
146923183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
147023183910SDouglas Gilbert 			arr[3] = n - 4;
147123183910SDouglas Gilbert 			break;
147223183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
147323183910SDouglas Gilbert 			n = 4;
147423183910SDouglas Gilbert 			arr[n++] = 0x2f;
147523183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
147623183910SDouglas Gilbert 			arr[3] = n - 4;
147723183910SDouglas Gilbert 			break;
147823183910SDouglas Gilbert 		default:
147923183910SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
148023183910SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
148123183910SDouglas Gilbert 			return check_condition_result;
148223183910SDouglas Gilbert 		}
148323183910SDouglas Gilbert 	} else {
148423183910SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
148523183910SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
148623183910SDouglas Gilbert 		return check_condition_result;
148723183910SDouglas Gilbert 	}
1488c65b1445SDouglas Gilbert 	len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1489c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1490c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
1491c65b1445SDouglas Gilbert }
1492c65b1445SDouglas Gilbert 
149319789100SFUJITA Tomonori static int check_device_access_params(struct sdebug_dev_info *devi,
149419789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
14951da177e4SLinus Torvalds {
1496c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
149719789100SFUJITA Tomonori 		mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
14981da177e4SLinus Torvalds 		return check_condition_result;
14991da177e4SLinus Torvalds 	}
1500c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
1501c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
150219789100SFUJITA Tomonori 		mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
1503c65b1445SDouglas Gilbert 		return check_condition_result;
1504c65b1445SDouglas Gilbert 	}
150519789100SFUJITA Tomonori 	return 0;
150619789100SFUJITA Tomonori }
150719789100SFUJITA Tomonori 
150819789100SFUJITA Tomonori static int do_device_access(struct scsi_cmnd *scmd,
150919789100SFUJITA Tomonori 			    struct sdebug_dev_info *devi,
151019789100SFUJITA Tomonori 			    unsigned long long lba, unsigned int num, int write)
151119789100SFUJITA Tomonori {
151219789100SFUJITA Tomonori 	int ret;
151319789100SFUJITA Tomonori 	unsigned int block, rest = 0;
151419789100SFUJITA Tomonori 	int (*func)(struct scsi_cmnd *, unsigned char *, int);
151519789100SFUJITA Tomonori 
151619789100SFUJITA Tomonori 	func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
151719789100SFUJITA Tomonori 
151819789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
151919789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
152019789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
152119789100SFUJITA Tomonori 
152219789100SFUJITA Tomonori 	ret = func(scmd, fake_storep + (block * SECT_SIZE),
152319789100SFUJITA Tomonori 		   (num - rest) * SECT_SIZE);
152419789100SFUJITA Tomonori 	if (!ret && rest)
152519789100SFUJITA Tomonori 		ret = func(scmd, fake_storep, rest * SECT_SIZE);
152619789100SFUJITA Tomonori 
152719789100SFUJITA Tomonori 	return ret;
152819789100SFUJITA Tomonori }
152919789100SFUJITA Tomonori 
153019789100SFUJITA Tomonori static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
153119789100SFUJITA Tomonori 		     unsigned int num, struct sdebug_dev_info *devip)
153219789100SFUJITA Tomonori {
153319789100SFUJITA Tomonori 	unsigned long iflags;
153419789100SFUJITA Tomonori 	int ret;
153519789100SFUJITA Tomonori 
153619789100SFUJITA Tomonori 	ret = check_device_access_params(devip, lba, num);
153719789100SFUJITA Tomonori 	if (ret)
153819789100SFUJITA Tomonori 		return ret;
153919789100SFUJITA Tomonori 
15401da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
1541c65b1445SDouglas Gilbert 	    (lba <= OPT_MEDIUM_ERR_ADDR) &&
1542c65b1445SDouglas Gilbert 	    ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1543c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
15441da177e4SLinus Torvalds 		mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
15451da177e4SLinus Torvalds 				0);
1546c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
1547c65b1445SDouglas Gilbert 		if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1548c65b1445SDouglas Gilbert 			devip->sense_buff[0] |= 0x80;	/* Valid bit */
1549c65b1445SDouglas Gilbert 			ret = OPT_MEDIUM_ERR_ADDR;
1550c65b1445SDouglas Gilbert 			devip->sense_buff[3] = (ret >> 24) & 0xff;
1551c65b1445SDouglas Gilbert 			devip->sense_buff[4] = (ret >> 16) & 0xff;
1552c65b1445SDouglas Gilbert 			devip->sense_buff[5] = (ret >> 8) & 0xff;
1553c65b1445SDouglas Gilbert 			devip->sense_buff[6] = ret & 0xff;
1554c65b1445SDouglas Gilbert 		}
15551da177e4SLinus Torvalds 		return check_condition_result;
15561da177e4SLinus Torvalds 	}
15571da177e4SLinus Torvalds 	read_lock_irqsave(&atomic_rw, iflags);
155819789100SFUJITA Tomonori 	ret = do_device_access(SCpnt, devip, lba, num, 0);
15591da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
15601da177e4SLinus Torvalds 	return ret;
15611da177e4SLinus Torvalds }
15621da177e4SLinus Torvalds 
1563c65b1445SDouglas Gilbert static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
1564c65b1445SDouglas Gilbert 		      unsigned int num, struct sdebug_dev_info *devip)
15651da177e4SLinus Torvalds {
15661da177e4SLinus Torvalds 	unsigned long iflags;
156719789100SFUJITA Tomonori 	int ret;
15681da177e4SLinus Torvalds 
156919789100SFUJITA Tomonori 	ret = check_device_access_params(devip, lba, num);
157019789100SFUJITA Tomonori 	if (ret)
157119789100SFUJITA Tomonori 		return ret;
15721da177e4SLinus Torvalds 
15731da177e4SLinus Torvalds 	write_lock_irqsave(&atomic_rw, iflags);
157419789100SFUJITA Tomonori 	ret = do_device_access(SCpnt, devip, lba, num, 1);
15751da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
157619789100SFUJITA Tomonori 	if (-1 == ret)
15771da177e4SLinus Torvalds 		return (DID_ERROR << 16);
157819789100SFUJITA Tomonori 	else if ((ret < (num * SECT_SIZE)) &&
15791da177e4SLinus Torvalds 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1580c65b1445SDouglas Gilbert 		printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
158119789100SFUJITA Tomonori 		       " IO sent=%d bytes\n", num * SECT_SIZE, ret);
15821da177e4SLinus Torvalds 	return 0;
15831da177e4SLinus Torvalds }
15841da177e4SLinus Torvalds 
1585c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256
15861da177e4SLinus Torvalds 
15871da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp,
15881da177e4SLinus Torvalds 			    struct sdebug_dev_info * devip)
15891da177e4SLinus Torvalds {
15901da177e4SLinus Torvalds 	unsigned int alloc_len;
1591c65b1445SDouglas Gilbert 	int lun_cnt, i, upper, num, n, wlun, lun;
15921da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
15931da177e4SLinus Torvalds 	int select_report = (int)cmd[2];
15941da177e4SLinus Torvalds 	struct scsi_lun *one_lun;
15951da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_RLUN_ARR_SZ];
1596c65b1445SDouglas Gilbert 	unsigned char * max_addr;
15971da177e4SLinus Torvalds 
15981da177e4SLinus Torvalds 	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
1599c65b1445SDouglas Gilbert 	if ((alloc_len < 4) || (select_report > 2)) {
16001da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
16011da177e4SLinus Torvalds 			       	0);
16021da177e4SLinus Torvalds 		return check_condition_result;
16031da177e4SLinus Torvalds 	}
16041da177e4SLinus Torvalds 	/* can produce response with up to 16k luns (lun 0 to lun 16383) */
16051da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
16061da177e4SLinus Torvalds 	lun_cnt = scsi_debug_max_luns;
1607c65b1445SDouglas Gilbert 	if (1 == select_report)
1608c65b1445SDouglas Gilbert 		lun_cnt = 0;
1609c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1610c65b1445SDouglas Gilbert 		--lun_cnt;
1611c65b1445SDouglas Gilbert 	wlun = (select_report > 0) ? 1 : 0;
1612c65b1445SDouglas Gilbert 	num = lun_cnt + wlun;
1613c65b1445SDouglas Gilbert 	arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1614c65b1445SDouglas Gilbert 	arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1615c65b1445SDouglas Gilbert 	n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1616c65b1445SDouglas Gilbert 			    sizeof(struct scsi_lun)), num);
1617c65b1445SDouglas Gilbert 	if (n < num) {
1618c65b1445SDouglas Gilbert 		wlun = 0;
1619c65b1445SDouglas Gilbert 		lun_cnt = n;
1620c65b1445SDouglas Gilbert 	}
16211da177e4SLinus Torvalds 	one_lun = (struct scsi_lun *) &arr[8];
1622c65b1445SDouglas Gilbert 	max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1623c65b1445SDouglas Gilbert 	for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1624c65b1445SDouglas Gilbert              ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1625c65b1445SDouglas Gilbert 	     i++, lun++) {
1626c65b1445SDouglas Gilbert 		upper = (lun >> 8) & 0x3f;
16271da177e4SLinus Torvalds 		if (upper)
16281da177e4SLinus Torvalds 			one_lun[i].scsi_lun[0] =
16291da177e4SLinus Torvalds 			    (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
1630c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = lun & 0xff;
16311da177e4SLinus Torvalds 	}
1632c65b1445SDouglas Gilbert 	if (wlun) {
1633c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1634c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1635c65b1445SDouglas Gilbert 		i++;
1636c65b1445SDouglas Gilbert 	}
1637c65b1445SDouglas Gilbert 	alloc_len = (unsigned char *)(one_lun + i) - arr;
16381da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr,
16391da177e4SLinus Torvalds 				    min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
16401da177e4SLinus Torvalds }
16411da177e4SLinus Torvalds 
1642c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
1643c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
1644c639d14eSFUJITA Tomonori {
1645c639d14eSFUJITA Tomonori 	int i, j, ret = -1;
1646c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
1647c639d14eSFUJITA Tomonori 	unsigned int offset;
1648c639d14eSFUJITA Tomonori 	struct scatterlist *sg;
1649c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
1650c639d14eSFUJITA Tomonori 
1651c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
1652c639d14eSFUJITA Tomonori 	buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
1653c639d14eSFUJITA Tomonori 	if (!buf)
1654c639d14eSFUJITA Tomonori 		return ret;
1655c639d14eSFUJITA Tomonori 
165621a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
1657c639d14eSFUJITA Tomonori 
1658c639d14eSFUJITA Tomonori 	offset = 0;
1659c639d14eSFUJITA Tomonori 	for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
1660c639d14eSFUJITA Tomonori 		kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1661c639d14eSFUJITA Tomonori 		if (!kaddr)
1662c639d14eSFUJITA Tomonori 			goto out;
1663c639d14eSFUJITA Tomonori 
1664c639d14eSFUJITA Tomonori 		for (j = 0; j < sg->length; j++)
1665c639d14eSFUJITA Tomonori 			*(kaddr + sg->offset + j) ^= *(buf + offset + j);
1666c639d14eSFUJITA Tomonori 
1667c639d14eSFUJITA Tomonori 		offset += sg->length;
1668c639d14eSFUJITA Tomonori 		kunmap_atomic(kaddr, KM_USER0);
1669c639d14eSFUJITA Tomonori 	}
1670c639d14eSFUJITA Tomonori 	ret = 0;
1671c639d14eSFUJITA Tomonori out:
1672c639d14eSFUJITA Tomonori 	kfree(buf);
1673c639d14eSFUJITA Tomonori 
1674c639d14eSFUJITA Tomonori 	return ret;
1675c639d14eSFUJITA Tomonori }
1676c639d14eSFUJITA Tomonori 
16771da177e4SLinus Torvalds /* When timer goes off this function is called. */
16781da177e4SLinus Torvalds static void timer_intr_handler(unsigned long indx)
16791da177e4SLinus Torvalds {
16801da177e4SLinus Torvalds 	struct sdebug_queued_cmd * sqcp;
16811da177e4SLinus Torvalds 	unsigned long iflags;
16821da177e4SLinus Torvalds 
16831da177e4SLinus Torvalds 	if (indx >= SCSI_DEBUG_CANQUEUE) {
16841da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
16851da177e4SLinus Torvalds 		       "large\n");
16861da177e4SLinus Torvalds 		return;
16871da177e4SLinus Torvalds 	}
16881da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
16891da177e4SLinus Torvalds 	sqcp = &queued_arr[(int)indx];
16901da177e4SLinus Torvalds 	if (! sqcp->in_use) {
16911da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
16921da177e4SLinus Torvalds 		       "interrupt\n");
16931da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
16941da177e4SLinus Torvalds 		return;
16951da177e4SLinus Torvalds 	}
16961da177e4SLinus Torvalds 	sqcp->in_use = 0;
16971da177e4SLinus Torvalds 	if (sqcp->done_funct) {
16981da177e4SLinus Torvalds 		sqcp->a_cmnd->result = sqcp->scsi_result;
16991da177e4SLinus Torvalds 		sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
17001da177e4SLinus Torvalds 	}
17011da177e4SLinus Torvalds 	sqcp->done_funct = NULL;
17021da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
17031da177e4SLinus Torvalds }
17041da177e4SLinus Torvalds 
17051da177e4SLinus Torvalds 
17068dea0d02SFUJITA Tomonori static struct sdebug_dev_info *
17078dea0d02SFUJITA Tomonori sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
17085cb2fc06SFUJITA Tomonori {
17095cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
17105cb2fc06SFUJITA Tomonori 
17115cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
17125cb2fc06SFUJITA Tomonori 	if (devip) {
17135cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
17145cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
17155cb2fc06SFUJITA Tomonori 	}
17165cb2fc06SFUJITA Tomonori 	return devip;
17175cb2fc06SFUJITA Tomonori }
17185cb2fc06SFUJITA Tomonori 
17191da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
17201da177e4SLinus Torvalds {
17211da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
17221da177e4SLinus Torvalds 	struct sdebug_dev_info * open_devip = NULL;
17231da177e4SLinus Torvalds 	struct sdebug_dev_info * devip =
17241da177e4SLinus Torvalds 			(struct sdebug_dev_info *)sdev->hostdata;
17251da177e4SLinus Torvalds 
17261da177e4SLinus Torvalds 	if (devip)
17271da177e4SLinus Torvalds 		return devip;
1728d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
17291da177e4SLinus Torvalds 	if (!sdbg_host) {
17301da177e4SLinus Torvalds                 printk(KERN_ERR "Host info NULL\n");
17311da177e4SLinus Torvalds 		return NULL;
17321da177e4SLinus Torvalds         }
17331da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
17341da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
17351da177e4SLinus Torvalds                     (devip->target == sdev->id) &&
17361da177e4SLinus Torvalds                     (devip->lun == sdev->lun))
17371da177e4SLinus Torvalds                         return devip;
17381da177e4SLinus Torvalds 		else {
17391da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
17401da177e4SLinus Torvalds 				open_devip = devip;
17411da177e4SLinus Torvalds 		}
17421da177e4SLinus Torvalds 	}
17435cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
17445cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
17455cb2fc06SFUJITA Tomonori 		if (!open_devip) {
17461da177e4SLinus Torvalds 			printk(KERN_ERR "%s: out of memory at line %d\n",
17471da177e4SLinus Torvalds 				__FUNCTION__, __LINE__);
17481da177e4SLinus Torvalds 			return NULL;
17491da177e4SLinus Torvalds 		}
17501da177e4SLinus Torvalds 	}
1751a75869d1SFUJITA Tomonori 
17521da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
17531da177e4SLinus Torvalds 	open_devip->target = sdev->id;
17541da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
17551da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
17561da177e4SLinus Torvalds 	open_devip->reset = 1;
17571da177e4SLinus Torvalds 	open_devip->used = 1;
17581da177e4SLinus Torvalds 	memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
17591da177e4SLinus Torvalds 	if (scsi_debug_dsense)
17601da177e4SLinus Torvalds 		open_devip->sense_buff[0] = 0x72;
17611da177e4SLinus Torvalds 	else {
17621da177e4SLinus Torvalds 		open_devip->sense_buff[0] = 0x70;
17631da177e4SLinus Torvalds 		open_devip->sense_buff[7] = 0xa;
17641da177e4SLinus Torvalds 	}
1765c65b1445SDouglas Gilbert 	if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
1766c65b1445SDouglas Gilbert 		open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
1767a75869d1SFUJITA Tomonori 
17681da177e4SLinus Torvalds 	return open_devip;
17691da177e4SLinus Torvalds }
17701da177e4SLinus Torvalds 
17718dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
17721da177e4SLinus Torvalds {
17738dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
17748dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
17758dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
177675ad23bcSNick Piggin 	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
17778dea0d02SFUJITA Tomonori 	return 0;
17788dea0d02SFUJITA Tomonori }
17791da177e4SLinus Torvalds 
17808dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
17818dea0d02SFUJITA Tomonori {
17828dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip;
1783a34c4e98SFUJITA Tomonori 
17841da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
17858dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
17868dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
17878dea0d02SFUJITA Tomonori 	if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
17888dea0d02SFUJITA Tomonori 		sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
17898dea0d02SFUJITA Tomonori 	devip = devInfoReg(sdp);
17908dea0d02SFUJITA Tomonori 	if (NULL == devip)
17918dea0d02SFUJITA Tomonori 		return 1;	/* no resources, will be marked offline */
17928dea0d02SFUJITA Tomonori 	sdp->hostdata = devip;
17938dea0d02SFUJITA Tomonori 	if (sdp->host->cmd_per_lun)
17948dea0d02SFUJITA Tomonori 		scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
17958dea0d02SFUJITA Tomonori 					sdp->host->cmd_per_lun);
17968dea0d02SFUJITA Tomonori 	blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
17978dea0d02SFUJITA Tomonori 	return 0;
17988dea0d02SFUJITA Tomonori }
17998dea0d02SFUJITA Tomonori 
18008dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
18018dea0d02SFUJITA Tomonori {
18028dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
18038dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
18048dea0d02SFUJITA Tomonori 
18058dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
18068dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
18078dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
18088dea0d02SFUJITA Tomonori 	if (devip) {
18098dea0d02SFUJITA Tomonori 		/* make this slot avaliable for re-use */
18108dea0d02SFUJITA Tomonori 		devip->used = 0;
18118dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
18128dea0d02SFUJITA Tomonori 	}
18138dea0d02SFUJITA Tomonori }
18148dea0d02SFUJITA Tomonori 
18158dea0d02SFUJITA Tomonori /* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
18168dea0d02SFUJITA Tomonori static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
18178dea0d02SFUJITA Tomonori {
18188dea0d02SFUJITA Tomonori 	unsigned long iflags;
18198dea0d02SFUJITA Tomonori 	int k;
18208dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
18218dea0d02SFUJITA Tomonori 
18228dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
18238dea0d02SFUJITA Tomonori 	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
18248dea0d02SFUJITA Tomonori 		sqcp = &queued_arr[k];
18258dea0d02SFUJITA Tomonori 		if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
18268dea0d02SFUJITA Tomonori 			del_timer_sync(&sqcp->cmnd_timer);
18278dea0d02SFUJITA Tomonori 			sqcp->in_use = 0;
18288dea0d02SFUJITA Tomonori 			sqcp->a_cmnd = NULL;
18298dea0d02SFUJITA Tomonori 			break;
18308dea0d02SFUJITA Tomonori 		}
18318dea0d02SFUJITA Tomonori 	}
18328dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
18338dea0d02SFUJITA Tomonori 	return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
18348dea0d02SFUJITA Tomonori }
18358dea0d02SFUJITA Tomonori 
18368dea0d02SFUJITA Tomonori /* Deletes (stops) timers of all queued commands */
18378dea0d02SFUJITA Tomonori static void stop_all_queued(void)
18388dea0d02SFUJITA Tomonori {
18398dea0d02SFUJITA Tomonori 	unsigned long iflags;
18408dea0d02SFUJITA Tomonori 	int k;
18418dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
18428dea0d02SFUJITA Tomonori 
18438dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
18448dea0d02SFUJITA Tomonori 	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
18458dea0d02SFUJITA Tomonori 		sqcp = &queued_arr[k];
18468dea0d02SFUJITA Tomonori 		if (sqcp->in_use && sqcp->a_cmnd) {
18478dea0d02SFUJITA Tomonori 			del_timer_sync(&sqcp->cmnd_timer);
18488dea0d02SFUJITA Tomonori 			sqcp->in_use = 0;
18498dea0d02SFUJITA Tomonori 			sqcp->a_cmnd = NULL;
18508dea0d02SFUJITA Tomonori 		}
18518dea0d02SFUJITA Tomonori 	}
18528dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
18531da177e4SLinus Torvalds }
18541da177e4SLinus Torvalds 
18551da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
18561da177e4SLinus Torvalds {
18571da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
18581da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: abort\n");
18591da177e4SLinus Torvalds 	++num_aborts;
18601da177e4SLinus Torvalds 	stop_queued_cmnd(SCpnt);
18611da177e4SLinus Torvalds 	return SUCCESS;
18621da177e4SLinus Torvalds }
18631da177e4SLinus Torvalds 
18641da177e4SLinus Torvalds static int scsi_debug_biosparam(struct scsi_device *sdev,
18651da177e4SLinus Torvalds 		struct block_device * bdev, sector_t capacity, int *info)
18661da177e4SLinus Torvalds {
18671da177e4SLinus Torvalds 	int res;
18681da177e4SLinus Torvalds 	unsigned char *buf;
18691da177e4SLinus Torvalds 
18701da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
18711da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: biosparam\n");
18721da177e4SLinus Torvalds 	buf = scsi_bios_ptable(bdev);
18731da177e4SLinus Torvalds 	if (buf) {
18741da177e4SLinus Torvalds 		res = scsi_partsize(buf, capacity,
18751da177e4SLinus Torvalds 				    &info[2], &info[0], &info[1]);
18761da177e4SLinus Torvalds 		kfree(buf);
18771da177e4SLinus Torvalds 		if (! res)
18781da177e4SLinus Torvalds 			return res;
18791da177e4SLinus Torvalds 	}
18801da177e4SLinus Torvalds 	info[0] = sdebug_heads;
18811da177e4SLinus Torvalds 	info[1] = sdebug_sectors_per;
18821da177e4SLinus Torvalds 	info[2] = sdebug_cylinders_per;
18831da177e4SLinus Torvalds 	return 0;
18841da177e4SLinus Torvalds }
18851da177e4SLinus Torvalds 
18861da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
18871da177e4SLinus Torvalds {
18881da177e4SLinus Torvalds 	struct sdebug_dev_info * devip;
18891da177e4SLinus Torvalds 
18901da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
18911da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: device_reset\n");
18921da177e4SLinus Torvalds 	++num_dev_resets;
18931da177e4SLinus Torvalds 	if (SCpnt) {
18941da177e4SLinus Torvalds 		devip = devInfoReg(SCpnt->device);
18951da177e4SLinus Torvalds 		if (devip)
18961da177e4SLinus Torvalds 			devip->reset = 1;
18971da177e4SLinus Torvalds 	}
18981da177e4SLinus Torvalds 	return SUCCESS;
18991da177e4SLinus Torvalds }
19001da177e4SLinus Torvalds 
19011da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
19021da177e4SLinus Torvalds {
19031da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
19041da177e4SLinus Torvalds         struct sdebug_dev_info * dev_info;
19051da177e4SLinus Torvalds         struct scsi_device * sdp;
19061da177e4SLinus Torvalds         struct Scsi_Host * hp;
19071da177e4SLinus Torvalds 
19081da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
19091da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: bus_reset\n");
19101da177e4SLinus Torvalds 	++num_bus_resets;
19111da177e4SLinus Torvalds 	if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
1912d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
19131da177e4SLinus Torvalds 		if (sdbg_host) {
19141da177e4SLinus Torvalds 			list_for_each_entry(dev_info,
19151da177e4SLinus Torvalds                                             &sdbg_host->dev_info_list,
19161da177e4SLinus Torvalds                                             dev_list)
19171da177e4SLinus Torvalds 				dev_info->reset = 1;
19181da177e4SLinus Torvalds 		}
19191da177e4SLinus Torvalds 	}
19201da177e4SLinus Torvalds 	return SUCCESS;
19211da177e4SLinus Torvalds }
19221da177e4SLinus Torvalds 
19231da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
19241da177e4SLinus Torvalds {
19251da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
19261da177e4SLinus Torvalds         struct sdebug_dev_info * dev_info;
19271da177e4SLinus Torvalds 
19281da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
19291da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: host_reset\n");
19301da177e4SLinus Torvalds 	++num_host_resets;
19311da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
19321da177e4SLinus Torvalds         list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
19331da177e4SLinus Torvalds                 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
19341da177e4SLinus Torvalds                                     dev_list)
19351da177e4SLinus Torvalds                         dev_info->reset = 1;
19361da177e4SLinus Torvalds         }
19371da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
19381da177e4SLinus Torvalds 	stop_all_queued();
19391da177e4SLinus Torvalds 	return SUCCESS;
19401da177e4SLinus Torvalds }
19411da177e4SLinus Torvalds 
19421da177e4SLinus Torvalds /* Initializes timers in queued array */
19431da177e4SLinus Torvalds static void __init init_all_queued(void)
19441da177e4SLinus Torvalds {
19451da177e4SLinus Torvalds 	unsigned long iflags;
19461da177e4SLinus Torvalds 	int k;
19471da177e4SLinus Torvalds 	struct sdebug_queued_cmd * sqcp;
19481da177e4SLinus Torvalds 
19491da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
19501da177e4SLinus Torvalds 	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
19511da177e4SLinus Torvalds 		sqcp = &queued_arr[k];
19521da177e4SLinus Torvalds 		init_timer(&sqcp->cmnd_timer);
19531da177e4SLinus Torvalds 		sqcp->in_use = 0;
19541da177e4SLinus Torvalds 		sqcp->a_cmnd = NULL;
19551da177e4SLinus Torvalds 	}
19561da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
19571da177e4SLinus Torvalds }
19581da177e4SLinus Torvalds 
1959f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
19605f2578e5SFUJITA Tomonori 				      unsigned long store_size)
19611da177e4SLinus Torvalds {
19621da177e4SLinus Torvalds 	struct partition * pp;
19631da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
19641da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
19651da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
19661da177e4SLinus Torvalds 
19671da177e4SLinus Torvalds 	/* assume partition table already zeroed */
1968f58b0efbSFUJITA Tomonori 	if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
19691da177e4SLinus Torvalds 		return;
19701da177e4SLinus Torvalds 	if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
19711da177e4SLinus Torvalds 		scsi_debug_num_parts = SDEBUG_MAX_PARTS;
19721da177e4SLinus Torvalds 		printk(KERN_WARNING "scsi_debug:build_parts: reducing "
19731da177e4SLinus Torvalds 				    "partitions to %d\n", SDEBUG_MAX_PARTS);
19741da177e4SLinus Torvalds 	}
1975c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
19761da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
19771da177e4SLinus Torvalds 			   / scsi_debug_num_parts;
19781da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
19791da177e4SLinus Torvalds         starts[0] = sdebug_sectors_per;
19801da177e4SLinus Torvalds 	for (k = 1; k < scsi_debug_num_parts; ++k)
19811da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
19821da177e4SLinus Torvalds 			    * heads_by_sects;
19831da177e4SLinus Torvalds 	starts[scsi_debug_num_parts] = num_sectors;
19841da177e4SLinus Torvalds 	starts[scsi_debug_num_parts + 1] = 0;
19851da177e4SLinus Torvalds 
19861da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
19871da177e4SLinus Torvalds 	ramp[511] = 0xAA;
19881da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
19891da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
19901da177e4SLinus Torvalds 		start_sec = starts[k];
19911da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
19921da177e4SLinus Torvalds 		pp->boot_ind = 0;
19931da177e4SLinus Torvalds 
19941da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
19951da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
19961da177e4SLinus Torvalds 			   / sdebug_sectors_per;
19971da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
19981da177e4SLinus Torvalds 
19991da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
20001da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
20011da177e4SLinus Torvalds 			       / sdebug_sectors_per;
20021da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
20031da177e4SLinus Torvalds 
20041da177e4SLinus Torvalds 		pp->start_sect = start_sec;
20051da177e4SLinus Torvalds 		pp->nr_sects = end_sec - start_sec + 1;
20061da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
20071da177e4SLinus Torvalds 	}
20081da177e4SLinus Torvalds }
20091da177e4SLinus Torvalds 
20101da177e4SLinus Torvalds static int schedule_resp(struct scsi_cmnd * cmnd,
20111da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip,
20121da177e4SLinus Torvalds 			 done_funct_t done, int scsi_result, int delta_jiff)
20131da177e4SLinus Torvalds {
20141da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
20151da177e4SLinus Torvalds 		if (scsi_result) {
20161da177e4SLinus Torvalds 			struct scsi_device * sdp = cmnd->device;
20171da177e4SLinus Torvalds 
2018c65b1445SDouglas Gilbert 			printk(KERN_INFO "scsi_debug:    <%u %u %u %u> "
2019c65b1445SDouglas Gilbert 			       "non-zero result=0x%x\n", sdp->host->host_no,
2020c65b1445SDouglas Gilbert 			       sdp->channel, sdp->id, sdp->lun, scsi_result);
20211da177e4SLinus Torvalds 		}
20221da177e4SLinus Torvalds 	}
20231da177e4SLinus Torvalds 	if (cmnd && devip) {
20241da177e4SLinus Torvalds 		/* simulate autosense by this driver */
20251da177e4SLinus Torvalds 		if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
20261da177e4SLinus Torvalds 			memcpy(cmnd->sense_buffer, devip->sense_buff,
20271da177e4SLinus Torvalds 			       (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
20281da177e4SLinus Torvalds 			       SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
20291da177e4SLinus Torvalds 	}
20301da177e4SLinus Torvalds 	if (delta_jiff <= 0) {
20311da177e4SLinus Torvalds 		if (cmnd)
20321da177e4SLinus Torvalds 			cmnd->result = scsi_result;
20331da177e4SLinus Torvalds 		if (done)
20341da177e4SLinus Torvalds 			done(cmnd);
20351da177e4SLinus Torvalds 		return 0;
20361da177e4SLinus Torvalds 	} else {
20371da177e4SLinus Torvalds 		unsigned long iflags;
20381da177e4SLinus Torvalds 		int k;
20391da177e4SLinus Torvalds 		struct sdebug_queued_cmd * sqcp = NULL;
20401da177e4SLinus Torvalds 
20411da177e4SLinus Torvalds 		spin_lock_irqsave(&queued_arr_lock, iflags);
20421da177e4SLinus Torvalds 		for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
20431da177e4SLinus Torvalds 			sqcp = &queued_arr[k];
20441da177e4SLinus Torvalds 			if (! sqcp->in_use)
20451da177e4SLinus Torvalds 				break;
20461da177e4SLinus Torvalds 		}
20471da177e4SLinus Torvalds 		if (k >= SCSI_DEBUG_CANQUEUE) {
20481da177e4SLinus Torvalds 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
20491da177e4SLinus Torvalds 			printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
20501da177e4SLinus Torvalds 			return 1;	/* report busy to mid level */
20511da177e4SLinus Torvalds 		}
20521da177e4SLinus Torvalds 		sqcp->in_use = 1;
20531da177e4SLinus Torvalds 		sqcp->a_cmnd = cmnd;
20541da177e4SLinus Torvalds 		sqcp->scsi_result = scsi_result;
20551da177e4SLinus Torvalds 		sqcp->done_funct = done;
20561da177e4SLinus Torvalds 		sqcp->cmnd_timer.function = timer_intr_handler;
20571da177e4SLinus Torvalds 		sqcp->cmnd_timer.data = k;
20581da177e4SLinus Torvalds 		sqcp->cmnd_timer.expires = jiffies + delta_jiff;
20591da177e4SLinus Torvalds 		add_timer(&sqcp->cmnd_timer);
20601da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
20611da177e4SLinus Torvalds 		if (cmnd)
20621da177e4SLinus Torvalds 			cmnd->result = 0;
20631da177e4SLinus Torvalds 		return 0;
20641da177e4SLinus Torvalds 	}
20651da177e4SLinus Torvalds }
206623183910SDouglas Gilbert /* Note: The following macros create attribute files in the
206723183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
206823183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
206923183910SDouglas Gilbert    as it can when the corresponding attribute in the
207023183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
207123183910SDouglas Gilbert  */
2072c65b1445SDouglas Gilbert module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2073c65b1445SDouglas Gilbert module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2074c65b1445SDouglas Gilbert module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2075c65b1445SDouglas Gilbert module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2076c65b1445SDouglas Gilbert module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
207723183910SDouglas Gilbert module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
2078c65b1445SDouglas Gilbert module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2079c65b1445SDouglas Gilbert module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2080c65b1445SDouglas Gilbert module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2081c65b1445SDouglas Gilbert module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2082c65b1445SDouglas Gilbert module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2083c65b1445SDouglas Gilbert module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2084c65b1445SDouglas Gilbert module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2085c65b1445SDouglas Gilbert module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
208623183910SDouglas Gilbert module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
208723183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
20881da177e4SLinus Torvalds 
20891da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
20901da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
20911da177e4SLinus Torvalds MODULE_LICENSE("GPL");
20921da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION);
20931da177e4SLinus Torvalds 
20941da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
20951da177e4SLinus Torvalds MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
2096c65b1445SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2097c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
2098beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
209923183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
2100c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2101c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
21021da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
2103c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
21046f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
21051da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
21061da177e4SLinus Torvalds MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
2107c65b1445SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
210823183910SDouglas Gilbert MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
21091da177e4SLinus Torvalds 
21101da177e4SLinus Torvalds 
21111da177e4SLinus Torvalds static char sdebug_info[256];
21121da177e4SLinus Torvalds 
21131da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp)
21141da177e4SLinus Torvalds {
21151da177e4SLinus Torvalds 	sprintf(sdebug_info, "scsi_debug, version %s [%s], "
21161da177e4SLinus Torvalds 		"dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
21171da177e4SLinus Torvalds 		scsi_debug_version_date, scsi_debug_dev_size_mb,
21181da177e4SLinus Torvalds 		scsi_debug_opts);
21191da177e4SLinus Torvalds 	return sdebug_info;
21201da177e4SLinus Torvalds }
21211da177e4SLinus Torvalds 
21221da177e4SLinus Torvalds /* scsi_debug_proc_info
21231da177e4SLinus Torvalds  * Used if the driver currently has no own support for /proc/scsi
21241da177e4SLinus Torvalds  */
21251da177e4SLinus Torvalds static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
21261da177e4SLinus Torvalds 				int length, int inout)
21271da177e4SLinus Torvalds {
21281da177e4SLinus Torvalds 	int len, pos, begin;
21291da177e4SLinus Torvalds 	int orig_length;
21301da177e4SLinus Torvalds 
21311da177e4SLinus Torvalds 	orig_length = length;
21321da177e4SLinus Torvalds 
21331da177e4SLinus Torvalds 	if (inout == 1) {
21341da177e4SLinus Torvalds 		char arr[16];
21351da177e4SLinus Torvalds 		int minLen = length > 15 ? 15 : length;
21361da177e4SLinus Torvalds 
21371da177e4SLinus Torvalds 		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
21381da177e4SLinus Torvalds 			return -EACCES;
21391da177e4SLinus Torvalds 		memcpy(arr, buffer, minLen);
21401da177e4SLinus Torvalds 		arr[minLen] = '\0';
21411da177e4SLinus Torvalds 		if (1 != sscanf(arr, "%d", &pos))
21421da177e4SLinus Torvalds 			return -EINVAL;
21431da177e4SLinus Torvalds 		scsi_debug_opts = pos;
21441da177e4SLinus Torvalds 		if (scsi_debug_every_nth != 0)
21451da177e4SLinus Torvalds                         scsi_debug_cmnd_count = 0;
21461da177e4SLinus Torvalds 		return length;
21471da177e4SLinus Torvalds 	}
21481da177e4SLinus Torvalds 	begin = 0;
21491da177e4SLinus Torvalds 	pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
21501da177e4SLinus Torvalds 	    "%s [%s]\n"
21511da177e4SLinus Torvalds 	    "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
21521da177e4SLinus Torvalds 	    "every_nth=%d(curr:%d)\n"
21531da177e4SLinus Torvalds 	    "delay=%d, max_luns=%d, scsi_level=%d\n"
21541da177e4SLinus Torvalds 	    "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
21551da177e4SLinus Torvalds 	    "number of aborts=%d, device_reset=%d, bus_resets=%d, "
21561da177e4SLinus Torvalds 	    "host_resets=%d\n",
21571da177e4SLinus Torvalds 	    SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
21581da177e4SLinus Torvalds 	    scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
21591da177e4SLinus Torvalds 	    scsi_debug_cmnd_count, scsi_debug_delay,
21601da177e4SLinus Torvalds 	    scsi_debug_max_luns, scsi_debug_scsi_level,
21611da177e4SLinus Torvalds 	    SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
21621da177e4SLinus Torvalds 	    num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
21631da177e4SLinus Torvalds 	if (pos < offset) {
21641da177e4SLinus Torvalds 		len = 0;
21651da177e4SLinus Torvalds 		begin = pos;
21661da177e4SLinus Torvalds 	}
21671da177e4SLinus Torvalds 	*start = buffer + (offset - begin);	/* Start of wanted data */
21681da177e4SLinus Torvalds 	len -= (offset - begin);
21691da177e4SLinus Torvalds 	if (len > length)
21701da177e4SLinus Torvalds 		len = length;
21711da177e4SLinus Torvalds 	return len;
21721da177e4SLinus Torvalds }
21731da177e4SLinus Torvalds 
21741da177e4SLinus Torvalds static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
21751da177e4SLinus Torvalds {
21761da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
21771da177e4SLinus Torvalds }
21781da177e4SLinus Torvalds 
21791da177e4SLinus Torvalds static ssize_t sdebug_delay_store(struct device_driver * ddp,
21801da177e4SLinus Torvalds 				  const char * buf, size_t count)
21811da177e4SLinus Torvalds {
21821da177e4SLinus Torvalds         int delay;
21831da177e4SLinus Torvalds 	char work[20];
21841da177e4SLinus Torvalds 
21851da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
21861da177e4SLinus Torvalds 		if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
21871da177e4SLinus Torvalds 			scsi_debug_delay = delay;
21881da177e4SLinus Torvalds 			return count;
21891da177e4SLinus Torvalds 		}
21901da177e4SLinus Torvalds 	}
21911da177e4SLinus Torvalds 	return -EINVAL;
21921da177e4SLinus Torvalds }
21931da177e4SLinus Torvalds DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
21941da177e4SLinus Torvalds 	    sdebug_delay_store);
21951da177e4SLinus Torvalds 
21961da177e4SLinus Torvalds static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
21971da177e4SLinus Torvalds {
21981da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
21991da177e4SLinus Torvalds }
22001da177e4SLinus Torvalds 
22011da177e4SLinus Torvalds static ssize_t sdebug_opts_store(struct device_driver * ddp,
22021da177e4SLinus Torvalds 				 const char * buf, size_t count)
22031da177e4SLinus Torvalds {
22041da177e4SLinus Torvalds         int opts;
22051da177e4SLinus Torvalds 	char work[20];
22061da177e4SLinus Torvalds 
22071da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
22081da177e4SLinus Torvalds 		if (0 == strnicmp(work,"0x", 2)) {
22091da177e4SLinus Torvalds 			if (1 == sscanf(&work[2], "%x", &opts))
22101da177e4SLinus Torvalds 				goto opts_done;
22111da177e4SLinus Torvalds 		} else {
22121da177e4SLinus Torvalds 			if (1 == sscanf(work, "%d", &opts))
22131da177e4SLinus Torvalds 				goto opts_done;
22141da177e4SLinus Torvalds 		}
22151da177e4SLinus Torvalds 	}
22161da177e4SLinus Torvalds 	return -EINVAL;
22171da177e4SLinus Torvalds opts_done:
22181da177e4SLinus Torvalds 	scsi_debug_opts = opts;
22191da177e4SLinus Torvalds 	scsi_debug_cmnd_count = 0;
22201da177e4SLinus Torvalds 	return count;
22211da177e4SLinus Torvalds }
22221da177e4SLinus Torvalds DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
22231da177e4SLinus Torvalds 	    sdebug_opts_store);
22241da177e4SLinus Torvalds 
22251da177e4SLinus Torvalds static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
22261da177e4SLinus Torvalds {
22271da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
22281da177e4SLinus Torvalds }
22291da177e4SLinus Torvalds static ssize_t sdebug_ptype_store(struct device_driver * ddp,
22301da177e4SLinus Torvalds 				  const char * buf, size_t count)
22311da177e4SLinus Torvalds {
22321da177e4SLinus Torvalds         int n;
22331da177e4SLinus Torvalds 
22341da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
22351da177e4SLinus Torvalds 		scsi_debug_ptype = n;
22361da177e4SLinus Torvalds 		return count;
22371da177e4SLinus Torvalds 	}
22381da177e4SLinus Torvalds 	return -EINVAL;
22391da177e4SLinus Torvalds }
22401da177e4SLinus Torvalds DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
22411da177e4SLinus Torvalds 
22421da177e4SLinus Torvalds static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
22431da177e4SLinus Torvalds {
22441da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
22451da177e4SLinus Torvalds }
22461da177e4SLinus Torvalds static ssize_t sdebug_dsense_store(struct device_driver * ddp,
22471da177e4SLinus Torvalds 				  const char * buf, size_t count)
22481da177e4SLinus Torvalds {
22491da177e4SLinus Torvalds         int n;
22501da177e4SLinus Torvalds 
22511da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
22521da177e4SLinus Torvalds 		scsi_debug_dsense = n;
22531da177e4SLinus Torvalds 		return count;
22541da177e4SLinus Torvalds 	}
22551da177e4SLinus Torvalds 	return -EINVAL;
22561da177e4SLinus Torvalds }
22571da177e4SLinus Torvalds DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
22581da177e4SLinus Torvalds 	    sdebug_dsense_store);
22591da177e4SLinus Torvalds 
226023183910SDouglas Gilbert static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
226123183910SDouglas Gilbert {
226223183910SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
226323183910SDouglas Gilbert }
226423183910SDouglas Gilbert static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
226523183910SDouglas Gilbert 				    const char * buf, size_t count)
226623183910SDouglas Gilbert {
226723183910SDouglas Gilbert         int n;
226823183910SDouglas Gilbert 
226923183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
227023183910SDouglas Gilbert 		scsi_debug_fake_rw = n;
227123183910SDouglas Gilbert 		return count;
227223183910SDouglas Gilbert 	}
227323183910SDouglas Gilbert 	return -EINVAL;
227423183910SDouglas Gilbert }
227523183910SDouglas Gilbert DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
227623183910SDouglas Gilbert 	    sdebug_fake_rw_store);
227723183910SDouglas Gilbert 
2278c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2279c65b1445SDouglas Gilbert {
2280c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2281c65b1445SDouglas Gilbert }
2282c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2283c65b1445SDouglas Gilbert 				     const char * buf, size_t count)
2284c65b1445SDouglas Gilbert {
2285c65b1445SDouglas Gilbert         int n;
2286c65b1445SDouglas Gilbert 
2287c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2288c65b1445SDouglas Gilbert 		scsi_debug_no_lun_0 = n;
2289c65b1445SDouglas Gilbert 		return count;
2290c65b1445SDouglas Gilbert 	}
2291c65b1445SDouglas Gilbert 	return -EINVAL;
2292c65b1445SDouglas Gilbert }
2293c65b1445SDouglas Gilbert DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2294c65b1445SDouglas Gilbert 	    sdebug_no_lun_0_store);
2295c65b1445SDouglas Gilbert 
22961da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
22971da177e4SLinus Torvalds {
22981da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
22991da177e4SLinus Torvalds }
23001da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
23011da177e4SLinus Torvalds 				     const char * buf, size_t count)
23021da177e4SLinus Torvalds {
23031da177e4SLinus Torvalds         int n;
23041da177e4SLinus Torvalds 
23051da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
23061da177e4SLinus Torvalds 		scsi_debug_num_tgts = n;
23071da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
23081da177e4SLinus Torvalds 		return count;
23091da177e4SLinus Torvalds 	}
23101da177e4SLinus Torvalds 	return -EINVAL;
23111da177e4SLinus Torvalds }
23121da177e4SLinus Torvalds DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
23131da177e4SLinus Torvalds 	    sdebug_num_tgts_store);
23141da177e4SLinus Torvalds 
23151da177e4SLinus Torvalds static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
23161da177e4SLinus Torvalds {
23171da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
23181da177e4SLinus Torvalds }
23191da177e4SLinus Torvalds DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
23201da177e4SLinus Torvalds 
23211da177e4SLinus Torvalds static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
23221da177e4SLinus Torvalds {
23231da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
23241da177e4SLinus Torvalds }
23251da177e4SLinus Torvalds DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
23261da177e4SLinus Torvalds 
23271da177e4SLinus Torvalds static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
23281da177e4SLinus Torvalds {
23291da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
23301da177e4SLinus Torvalds }
23311da177e4SLinus Torvalds static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
23321da177e4SLinus Torvalds 				      const char * buf, size_t count)
23331da177e4SLinus Torvalds {
23341da177e4SLinus Torvalds         int nth;
23351da177e4SLinus Torvalds 
23361da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
23371da177e4SLinus Torvalds 		scsi_debug_every_nth = nth;
23381da177e4SLinus Torvalds 		scsi_debug_cmnd_count = 0;
23391da177e4SLinus Torvalds 		return count;
23401da177e4SLinus Torvalds 	}
23411da177e4SLinus Torvalds 	return -EINVAL;
23421da177e4SLinus Torvalds }
23431da177e4SLinus Torvalds DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
23441da177e4SLinus Torvalds 	    sdebug_every_nth_store);
23451da177e4SLinus Torvalds 
23461da177e4SLinus Torvalds static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
23471da177e4SLinus Torvalds {
23481da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
23491da177e4SLinus Torvalds }
23501da177e4SLinus Torvalds static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
23511da177e4SLinus Torvalds 				     const char * buf, size_t count)
23521da177e4SLinus Torvalds {
23531da177e4SLinus Torvalds         int n;
23541da177e4SLinus Torvalds 
23551da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
23561da177e4SLinus Torvalds 		scsi_debug_max_luns = n;
23571da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
23581da177e4SLinus Torvalds 		return count;
23591da177e4SLinus Torvalds 	}
23601da177e4SLinus Torvalds 	return -EINVAL;
23611da177e4SLinus Torvalds }
23621da177e4SLinus Torvalds DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
23631da177e4SLinus Torvalds 	    sdebug_max_luns_store);
23641da177e4SLinus Torvalds 
23651da177e4SLinus Torvalds static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
23661da177e4SLinus Torvalds {
23671da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
23681da177e4SLinus Torvalds }
23691da177e4SLinus Torvalds DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
23701da177e4SLinus Torvalds 
2371c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2372c65b1445SDouglas Gilbert {
2373c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2374c65b1445SDouglas Gilbert }
2375c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2376c65b1445SDouglas Gilbert 				       const char * buf, size_t count)
2377c65b1445SDouglas Gilbert {
2378c65b1445SDouglas Gilbert         int n;
2379c65b1445SDouglas Gilbert 
2380c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2381c65b1445SDouglas Gilbert 		scsi_debug_virtual_gb = n;
238228898873SFUJITA Tomonori 
238328898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
238428898873SFUJITA Tomonori 
2385c65b1445SDouglas Gilbert 		return count;
2386c65b1445SDouglas Gilbert 	}
2387c65b1445SDouglas Gilbert 	return -EINVAL;
2388c65b1445SDouglas Gilbert }
2389c65b1445SDouglas Gilbert DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2390c65b1445SDouglas Gilbert 	    sdebug_virtual_gb_store);
2391c65b1445SDouglas Gilbert 
23921da177e4SLinus Torvalds static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
23931da177e4SLinus Torvalds {
23941da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
23951da177e4SLinus Torvalds }
23961da177e4SLinus Torvalds 
23971da177e4SLinus Torvalds static ssize_t sdebug_add_host_store(struct device_driver * ddp,
23981da177e4SLinus Torvalds 				     const char * buf, size_t count)
23991da177e4SLinus Torvalds {
24001da177e4SLinus Torvalds 	int delta_hosts;
24011da177e4SLinus Torvalds 
2402f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
24031da177e4SLinus Torvalds 		return -EINVAL;
24041da177e4SLinus Torvalds 	if (delta_hosts > 0) {
24051da177e4SLinus Torvalds 		do {
24061da177e4SLinus Torvalds 			sdebug_add_adapter();
24071da177e4SLinus Torvalds 		} while (--delta_hosts);
24081da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
24091da177e4SLinus Torvalds 		do {
24101da177e4SLinus Torvalds 			sdebug_remove_adapter();
24111da177e4SLinus Torvalds 		} while (++delta_hosts);
24121da177e4SLinus Torvalds 	}
24131da177e4SLinus Torvalds 	return count;
24141da177e4SLinus Torvalds }
24151da177e4SLinus Torvalds DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
24161da177e4SLinus Torvalds 	    sdebug_add_host_store);
24171da177e4SLinus Torvalds 
241823183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
241923183910SDouglas Gilbert 					  char * buf)
242023183910SDouglas Gilbert {
242123183910SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
242223183910SDouglas Gilbert }
242323183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
242423183910SDouglas Gilbert 					   const char * buf, size_t count)
242523183910SDouglas Gilbert {
242623183910SDouglas Gilbert 	int n;
242723183910SDouglas Gilbert 
242823183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
242923183910SDouglas Gilbert 		scsi_debug_vpd_use_hostno = n;
243023183910SDouglas Gilbert 		return count;
243123183910SDouglas Gilbert 	}
243223183910SDouglas Gilbert 	return -EINVAL;
243323183910SDouglas Gilbert }
243423183910SDouglas Gilbert DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
243523183910SDouglas Gilbert 	    sdebug_vpd_use_hostno_store);
243623183910SDouglas Gilbert 
243723183910SDouglas Gilbert /* Note: The following function creates attribute files in the
243823183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
243923183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
244023183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
244123183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
244223183910SDouglas Gilbert  */
24436ecaff7fSRandy Dunlap static int do_create_driverfs_files(void)
24441da177e4SLinus Torvalds {
24456ecaff7fSRandy Dunlap 	int ret;
24466ecaff7fSRandy Dunlap 
24476ecaff7fSRandy Dunlap 	ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
24486ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
24496ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
24506ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
24516ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
245223183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
24536ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
245423183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
24556ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
245623183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
24576ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
24586ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
24596ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
246023183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
246123183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
24626ecaff7fSRandy Dunlap 	return ret;
24631da177e4SLinus Torvalds }
24641da177e4SLinus Torvalds 
24651da177e4SLinus Torvalds static void do_remove_driverfs_files(void)
24661da177e4SLinus Torvalds {
246723183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
246823183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
24691da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
24701da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
24711da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
24721da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
247323183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
247423183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
24751da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
247623183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
24771da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
24781da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
24791da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
24801da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
24811da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
24821da177e4SLinus Torvalds }
24831da177e4SLinus Torvalds 
24848dea0d02SFUJITA Tomonori static void pseudo_0_release(struct device *dev)
24858dea0d02SFUJITA Tomonori {
24868dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
24878dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
24888dea0d02SFUJITA Tomonori }
24898dea0d02SFUJITA Tomonori 
24908dea0d02SFUJITA Tomonori static struct device pseudo_primary = {
24918dea0d02SFUJITA Tomonori 	.bus_id		= "pseudo_0",
24928dea0d02SFUJITA Tomonori 	.release	= pseudo_0_release,
24938dea0d02SFUJITA Tomonori };
24948dea0d02SFUJITA Tomonori 
24951da177e4SLinus Torvalds static int __init scsi_debug_init(void)
24961da177e4SLinus Torvalds {
24975f2578e5SFUJITA Tomonori 	unsigned long sz;
24981da177e4SLinus Torvalds 	int host_to_add;
24991da177e4SLinus Torvalds 	int k;
25006ecaff7fSRandy Dunlap 	int ret;
25011da177e4SLinus Torvalds 
25021da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb < 1)
25031da177e4SLinus Torvalds 		scsi_debug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
25045f2578e5SFUJITA Tomonori 	sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
2505f58b0efbSFUJITA Tomonori 	sdebug_store_sectors = sz / SECT_SIZE;
250628898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
25071da177e4SLinus Torvalds 
25081da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
25091da177e4SLinus Torvalds 	sdebug_heads = 8;
25101da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
25111da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb >= 16)
25121da177e4SLinus Torvalds 		sdebug_heads = 32;
25131da177e4SLinus Torvalds 	else if (scsi_debug_dev_size_mb >= 256)
25141da177e4SLinus Torvalds 		sdebug_heads = 64;
25151da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
25161da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
25171da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
25181da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
25191da177e4SLinus Torvalds 		sdebug_heads = 255;
25201da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
25211da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
25221da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
25231da177e4SLinus Torvalds 	}
25241da177e4SLinus Torvalds 
25251da177e4SLinus Torvalds 	fake_storep = vmalloc(sz);
25261da177e4SLinus Torvalds 	if (NULL == fake_storep) {
25271da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
25281da177e4SLinus Torvalds 		return -ENOMEM;
25291da177e4SLinus Torvalds 	}
25301da177e4SLinus Torvalds 	memset(fake_storep, 0, sz);
25311da177e4SLinus Torvalds 	if (scsi_debug_num_parts > 0)
2532f58b0efbSFUJITA Tomonori 		sdebug_build_parts(fake_storep, sz);
25331da177e4SLinus Torvalds 
25346ecaff7fSRandy Dunlap 	ret = device_register(&pseudo_primary);
25356ecaff7fSRandy Dunlap 	if (ret < 0) {
25366ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
25376ecaff7fSRandy Dunlap 			ret);
25386ecaff7fSRandy Dunlap 		goto free_vm;
25396ecaff7fSRandy Dunlap 	}
25406ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
25416ecaff7fSRandy Dunlap 	if (ret < 0) {
25426ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
25436ecaff7fSRandy Dunlap 			ret);
25446ecaff7fSRandy Dunlap 		goto dev_unreg;
25456ecaff7fSRandy Dunlap 	}
25466ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
25476ecaff7fSRandy Dunlap 	if (ret < 0) {
25486ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
25496ecaff7fSRandy Dunlap 			ret);
25506ecaff7fSRandy Dunlap 		goto bus_unreg;
25516ecaff7fSRandy Dunlap 	}
25526ecaff7fSRandy Dunlap 	ret = do_create_driverfs_files();
25536ecaff7fSRandy Dunlap 	if (ret < 0) {
25546ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
25556ecaff7fSRandy Dunlap 			ret);
25566ecaff7fSRandy Dunlap 		goto del_files;
25576ecaff7fSRandy Dunlap 	}
25581da177e4SLinus Torvalds 
25596ecaff7fSRandy Dunlap 	init_all_queued();
25601da177e4SLinus Torvalds 
25611da177e4SLinus Torvalds 	host_to_add = scsi_debug_add_host;
25621da177e4SLinus Torvalds         scsi_debug_add_host = 0;
25631da177e4SLinus Torvalds 
25641da177e4SLinus Torvalds         for (k = 0; k < host_to_add; k++) {
25651da177e4SLinus Torvalds                 if (sdebug_add_adapter()) {
25661da177e4SLinus Torvalds                         printk(KERN_ERR "scsi_debug_init: "
25671da177e4SLinus Torvalds                                "sdebug_add_adapter failed k=%d\n", k);
25681da177e4SLinus Torvalds                         break;
25691da177e4SLinus Torvalds                 }
25701da177e4SLinus Torvalds         }
25711da177e4SLinus Torvalds 
25721da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
25731da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
25741da177e4SLinus Torvalds 		       scsi_debug_add_host);
25751da177e4SLinus Torvalds 	}
25761da177e4SLinus Torvalds 	return 0;
25776ecaff7fSRandy Dunlap 
25786ecaff7fSRandy Dunlap del_files:
25796ecaff7fSRandy Dunlap 	do_remove_driverfs_files();
25806ecaff7fSRandy Dunlap 	driver_unregister(&sdebug_driverfs_driver);
25816ecaff7fSRandy Dunlap bus_unreg:
25826ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
25836ecaff7fSRandy Dunlap dev_unreg:
25846ecaff7fSRandy Dunlap 	device_unregister(&pseudo_primary);
25856ecaff7fSRandy Dunlap free_vm:
25866ecaff7fSRandy Dunlap 	vfree(fake_storep);
25876ecaff7fSRandy Dunlap 
25886ecaff7fSRandy Dunlap 	return ret;
25891da177e4SLinus Torvalds }
25901da177e4SLinus Torvalds 
25911da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
25921da177e4SLinus Torvalds {
25931da177e4SLinus Torvalds 	int k = scsi_debug_add_host;
25941da177e4SLinus Torvalds 
25951da177e4SLinus Torvalds 	stop_all_queued();
25961da177e4SLinus Torvalds 	for (; k; k--)
25971da177e4SLinus Torvalds 		sdebug_remove_adapter();
25981da177e4SLinus Torvalds 	do_remove_driverfs_files();
25991da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
26001da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
26011da177e4SLinus Torvalds 	device_unregister(&pseudo_primary);
26021da177e4SLinus Torvalds 
26031da177e4SLinus Torvalds 	vfree(fake_storep);
26041da177e4SLinus Torvalds }
26051da177e4SLinus Torvalds 
26061da177e4SLinus Torvalds device_initcall(scsi_debug_init);
26071da177e4SLinus Torvalds module_exit(scsi_debug_exit);
26081da177e4SLinus Torvalds 
26091da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev)
26101da177e4SLinus Torvalds {
26111da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
26121da177e4SLinus Torvalds 
26131da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
26141da177e4SLinus Torvalds         kfree(sdbg_host);
26151da177e4SLinus Torvalds }
26161da177e4SLinus Torvalds 
26171da177e4SLinus Torvalds static int sdebug_add_adapter(void)
26181da177e4SLinus Torvalds {
26191da177e4SLinus Torvalds 	int k, devs_per_host;
26201da177e4SLinus Torvalds         int error = 0;
26211da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
26228b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
26231da177e4SLinus Torvalds 
262424669f75SJes Sorensen         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
26251da177e4SLinus Torvalds         if (NULL == sdbg_host) {
26261da177e4SLinus Torvalds                 printk(KERN_ERR "%s: out of memory at line %d\n",
26271da177e4SLinus Torvalds                        __FUNCTION__, __LINE__);
26281da177e4SLinus Torvalds                 return -ENOMEM;
26291da177e4SLinus Torvalds         }
26301da177e4SLinus Torvalds 
26311da177e4SLinus Torvalds         INIT_LIST_HEAD(&sdbg_host->dev_info_list);
26321da177e4SLinus Torvalds 
26331da177e4SLinus Torvalds 	devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
26341da177e4SLinus Torvalds         for (k = 0; k < devs_per_host; k++) {
26355cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
26365cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
26371da177e4SLinus Torvalds                         printk(KERN_ERR "%s: out of memory at line %d\n",
26381da177e4SLinus Torvalds                                __FUNCTION__, __LINE__);
26391da177e4SLinus Torvalds                         error = -ENOMEM;
26401da177e4SLinus Torvalds 			goto clean;
26411da177e4SLinus Torvalds                 }
26421da177e4SLinus Torvalds         }
26431da177e4SLinus Torvalds 
26441da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
26451da177e4SLinus Torvalds         list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
26461da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
26471da177e4SLinus Torvalds 
26481da177e4SLinus Torvalds         sdbg_host->dev.bus = &pseudo_lld_bus;
26491da177e4SLinus Torvalds         sdbg_host->dev.parent = &pseudo_primary;
26501da177e4SLinus Torvalds         sdbg_host->dev.release = &sdebug_release_adapter;
26511da177e4SLinus Torvalds         sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
26521da177e4SLinus Torvalds 
26531da177e4SLinus Torvalds         error = device_register(&sdbg_host->dev);
26541da177e4SLinus Torvalds 
26551da177e4SLinus Torvalds         if (error)
26561da177e4SLinus Torvalds 		goto clean;
26571da177e4SLinus Torvalds 
26581da177e4SLinus Torvalds 	++scsi_debug_add_host;
26591da177e4SLinus Torvalds         return error;
26601da177e4SLinus Torvalds 
26611da177e4SLinus Torvalds clean:
26628b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
26638b40228fSFUJITA Tomonori 				 dev_list) {
26641da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
26651da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
26661da177e4SLinus Torvalds 	}
26671da177e4SLinus Torvalds 
26681da177e4SLinus Torvalds 	kfree(sdbg_host);
26691da177e4SLinus Torvalds         return error;
26701da177e4SLinus Torvalds }
26711da177e4SLinus Torvalds 
26721da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
26731da177e4SLinus Torvalds {
26741da177e4SLinus Torvalds         struct sdebug_host_info * sdbg_host = NULL;
26751da177e4SLinus Torvalds 
26761da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
26771da177e4SLinus Torvalds         if (!list_empty(&sdebug_host_list)) {
26781da177e4SLinus Torvalds                 sdbg_host = list_entry(sdebug_host_list.prev,
26791da177e4SLinus Torvalds                                        struct sdebug_host_info, host_list);
26801da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
26811da177e4SLinus Torvalds 	}
26821da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
26831da177e4SLinus Torvalds 
26841da177e4SLinus Torvalds 	if (!sdbg_host)
26851da177e4SLinus Torvalds 		return;
26861da177e4SLinus Torvalds 
26871da177e4SLinus Torvalds         device_unregister(&sdbg_host->dev);
26881da177e4SLinus Torvalds         --scsi_debug_add_host;
26891da177e4SLinus Torvalds }
26901da177e4SLinus Torvalds 
2691639db475SFUJITA Tomonori static
2692639db475SFUJITA Tomonori int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
2693639db475SFUJITA Tomonori {
2694639db475SFUJITA Tomonori 	unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
2695639db475SFUJITA Tomonori 	int len, k;
2696639db475SFUJITA Tomonori 	unsigned int num;
2697639db475SFUJITA Tomonori 	unsigned long long lba;
2698639db475SFUJITA Tomonori 	int errsts = 0;
2699639db475SFUJITA Tomonori 	int target = SCpnt->device->id;
2700639db475SFUJITA Tomonori 	struct sdebug_dev_info *devip = NULL;
2701639db475SFUJITA Tomonori 	int inj_recovered = 0;
2702639db475SFUJITA Tomonori 	int inj_transport = 0;
2703639db475SFUJITA Tomonori 	int delay_override = 0;
2704639db475SFUJITA Tomonori 
2705639db475SFUJITA Tomonori 	scsi_set_resid(SCpnt, 0);
2706639db475SFUJITA Tomonori 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
2707639db475SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: cmd ");
2708639db475SFUJITA Tomonori 		for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
2709639db475SFUJITA Tomonori 			printk("%02x ", (int)cmd[k]);
2710639db475SFUJITA Tomonori 		printk("\n");
2711639db475SFUJITA Tomonori 	}
2712639db475SFUJITA Tomonori 
2713639db475SFUJITA Tomonori 	if (target == SCpnt->device->host->hostt->this_id) {
2714639db475SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: initiator's id used as "
2715639db475SFUJITA Tomonori 		       "target!\n");
2716639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
2717639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
2718639db475SFUJITA Tomonori 	}
2719639db475SFUJITA Tomonori 
2720639db475SFUJITA Tomonori 	if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
2721639db475SFUJITA Tomonori 	    (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
2722639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
2723639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
2724639db475SFUJITA Tomonori 	devip = devInfoReg(SCpnt->device);
2725639db475SFUJITA Tomonori 	if (NULL == devip)
2726639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
2727639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
2728639db475SFUJITA Tomonori 
2729639db475SFUJITA Tomonori 	if ((scsi_debug_every_nth != 0) &&
2730639db475SFUJITA Tomonori 	    (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
2731639db475SFUJITA Tomonori 		scsi_debug_cmnd_count = 0;
2732639db475SFUJITA Tomonori 		if (scsi_debug_every_nth < -1)
2733639db475SFUJITA Tomonori 			scsi_debug_every_nth = -1;
2734639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
2735639db475SFUJITA Tomonori 			return 0; /* ignore command causing timeout */
2736639db475SFUJITA Tomonori 		else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
2737639db475SFUJITA Tomonori 			inj_recovered = 1; /* to reads and writes below */
2738639db475SFUJITA Tomonori 		else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
2739639db475SFUJITA Tomonori 			inj_transport = 1; /* to reads and writes below */
2740639db475SFUJITA Tomonori 	}
2741639db475SFUJITA Tomonori 
2742639db475SFUJITA Tomonori 	if (devip->wlun) {
2743639db475SFUJITA Tomonori 		switch (*cmd) {
2744639db475SFUJITA Tomonori 		case INQUIRY:
2745639db475SFUJITA Tomonori 		case REQUEST_SENSE:
2746639db475SFUJITA Tomonori 		case TEST_UNIT_READY:
2747639db475SFUJITA Tomonori 		case REPORT_LUNS:
2748639db475SFUJITA Tomonori 			break;  /* only allowable wlun commands */
2749639db475SFUJITA Tomonori 		default:
2750639db475SFUJITA Tomonori 			if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2751639db475SFUJITA Tomonori 				printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
2752639db475SFUJITA Tomonori 				       "not supported for wlun\n", *cmd);
2753639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
2754639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
2755639db475SFUJITA Tomonori 			errsts = check_condition_result;
2756639db475SFUJITA Tomonori 			return schedule_resp(SCpnt, devip, done, errsts,
2757639db475SFUJITA Tomonori 					     0);
2758639db475SFUJITA Tomonori 		}
2759639db475SFUJITA Tomonori 	}
2760639db475SFUJITA Tomonori 
2761639db475SFUJITA Tomonori 	switch (*cmd) {
2762639db475SFUJITA Tomonori 	case INQUIRY:     /* mandatory, ignore unit attention */
2763639db475SFUJITA Tomonori 		delay_override = 1;
2764639db475SFUJITA Tomonori 		errsts = resp_inquiry(SCpnt, target, devip);
2765639db475SFUJITA Tomonori 		break;
2766639db475SFUJITA Tomonori 	case REQUEST_SENSE:	/* mandatory, ignore unit attention */
2767639db475SFUJITA Tomonori 		delay_override = 1;
2768639db475SFUJITA Tomonori 		errsts = resp_requests(SCpnt, devip);
2769639db475SFUJITA Tomonori 		break;
2770639db475SFUJITA Tomonori 	case REZERO_UNIT:	/* actually this is REWIND for SSC */
2771639db475SFUJITA Tomonori 	case START_STOP:
2772639db475SFUJITA Tomonori 		errsts = resp_start_stop(SCpnt, devip);
2773639db475SFUJITA Tomonori 		break;
2774639db475SFUJITA Tomonori 	case ALLOW_MEDIUM_REMOVAL:
2775639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2776639db475SFUJITA Tomonori 		if (errsts)
2777639db475SFUJITA Tomonori 			break;
2778639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2779639db475SFUJITA Tomonori 			printk(KERN_INFO "scsi_debug: Medium removal %s\n",
2780639db475SFUJITA Tomonori 			       cmd[4] ? "inhibited" : "enabled");
2781639db475SFUJITA Tomonori 		break;
2782639db475SFUJITA Tomonori 	case SEND_DIAGNOSTIC:     /* mandatory */
2783639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2784639db475SFUJITA Tomonori 		break;
2785639db475SFUJITA Tomonori 	case TEST_UNIT_READY:     /* mandatory */
2786639db475SFUJITA Tomonori 		delay_override = 1;
2787639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
2788639db475SFUJITA Tomonori 		break;
2789639db475SFUJITA Tomonori 	case RESERVE:
2790639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2791639db475SFUJITA Tomonori 		break;
2792639db475SFUJITA Tomonori 	case RESERVE_10:
2793639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2794639db475SFUJITA Tomonori 		break;
2795639db475SFUJITA Tomonori 	case RELEASE:
2796639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2797639db475SFUJITA Tomonori 		break;
2798639db475SFUJITA Tomonori 	case RELEASE_10:
2799639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2800639db475SFUJITA Tomonori 		break;
2801639db475SFUJITA Tomonori 	case READ_CAPACITY:
2802639db475SFUJITA Tomonori 		errsts = resp_readcap(SCpnt, devip);
2803639db475SFUJITA Tomonori 		break;
2804639db475SFUJITA Tomonori 	case SERVICE_ACTION_IN:
2805639db475SFUJITA Tomonori 		if (SAI_READ_CAPACITY_16 != cmd[1]) {
2806639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
2807639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
2808639db475SFUJITA Tomonori 			errsts = check_condition_result;
2809639db475SFUJITA Tomonori 			break;
2810639db475SFUJITA Tomonori 		}
2811639db475SFUJITA Tomonori 		errsts = resp_readcap16(SCpnt, devip);
2812639db475SFUJITA Tomonori 		break;
2813639db475SFUJITA Tomonori 	case MAINTENANCE_IN:
2814639db475SFUJITA Tomonori 		if (MI_REPORT_TARGET_PGS != cmd[1]) {
2815639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
2816639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
2817639db475SFUJITA Tomonori 			errsts = check_condition_result;
2818639db475SFUJITA Tomonori 			break;
2819639db475SFUJITA Tomonori 		}
2820639db475SFUJITA Tomonori 		errsts = resp_report_tgtpgs(SCpnt, devip);
2821639db475SFUJITA Tomonori 		break;
2822639db475SFUJITA Tomonori 	case READ_16:
2823639db475SFUJITA Tomonori 	case READ_12:
2824639db475SFUJITA Tomonori 	case READ_10:
2825639db475SFUJITA Tomonori 	case READ_6:
2826639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
2827639db475SFUJITA Tomonori 		if (errsts)
2828639db475SFUJITA Tomonori 			break;
2829639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
2830639db475SFUJITA Tomonori 			break;
2831639db475SFUJITA Tomonori 		get_data_transfer_info(cmd, &lba, &num);
2832639db475SFUJITA Tomonori 		errsts = resp_read(SCpnt, lba, num, devip);
2833639db475SFUJITA Tomonori 		if (inj_recovered && (0 == errsts)) {
2834639db475SFUJITA Tomonori 			mk_sense_buffer(devip, RECOVERED_ERROR,
2835639db475SFUJITA Tomonori 					THRESHOLD_EXCEEDED, 0);
2836639db475SFUJITA Tomonori 			errsts = check_condition_result;
2837639db475SFUJITA Tomonori 		} else if (inj_transport && (0 == errsts)) {
2838639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ABORTED_COMMAND,
2839639db475SFUJITA Tomonori 					TRANSPORT_PROBLEM, ACK_NAK_TO);
2840639db475SFUJITA Tomonori 			errsts = check_condition_result;
2841639db475SFUJITA Tomonori 		}
2842639db475SFUJITA Tomonori 		break;
2843639db475SFUJITA Tomonori 	case REPORT_LUNS:	/* mandatory, ignore unit attention */
2844639db475SFUJITA Tomonori 		delay_override = 1;
2845639db475SFUJITA Tomonori 		errsts = resp_report_luns(SCpnt, devip);
2846639db475SFUJITA Tomonori 		break;
2847639db475SFUJITA Tomonori 	case VERIFY:		/* 10 byte SBC-2 command */
2848639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
2849639db475SFUJITA Tomonori 		break;
2850639db475SFUJITA Tomonori 	case WRITE_16:
2851639db475SFUJITA Tomonori 	case WRITE_12:
2852639db475SFUJITA Tomonori 	case WRITE_10:
2853639db475SFUJITA Tomonori 	case WRITE_6:
2854639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
2855639db475SFUJITA Tomonori 		if (errsts)
2856639db475SFUJITA Tomonori 			break;
2857639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
2858639db475SFUJITA Tomonori 			break;
2859639db475SFUJITA Tomonori 		get_data_transfer_info(cmd, &lba, &num);
2860639db475SFUJITA Tomonori 		errsts = resp_write(SCpnt, lba, num, devip);
2861639db475SFUJITA Tomonori 		if (inj_recovered && (0 == errsts)) {
2862639db475SFUJITA Tomonori 			mk_sense_buffer(devip, RECOVERED_ERROR,
2863639db475SFUJITA Tomonori 					THRESHOLD_EXCEEDED, 0);
2864639db475SFUJITA Tomonori 			errsts = check_condition_result;
2865639db475SFUJITA Tomonori 		}
2866639db475SFUJITA Tomonori 		break;
2867639db475SFUJITA Tomonori 	case MODE_SENSE:
2868639db475SFUJITA Tomonori 	case MODE_SENSE_10:
2869639db475SFUJITA Tomonori 		errsts = resp_mode_sense(SCpnt, target, devip);
2870639db475SFUJITA Tomonori 		break;
2871639db475SFUJITA Tomonori 	case MODE_SELECT:
2872639db475SFUJITA Tomonori 		errsts = resp_mode_select(SCpnt, 1, devip);
2873639db475SFUJITA Tomonori 		break;
2874639db475SFUJITA Tomonori 	case MODE_SELECT_10:
2875639db475SFUJITA Tomonori 		errsts = resp_mode_select(SCpnt, 0, devip);
2876639db475SFUJITA Tomonori 		break;
2877639db475SFUJITA Tomonori 	case LOG_SENSE:
2878639db475SFUJITA Tomonori 		errsts = resp_log_sense(SCpnt, devip);
2879639db475SFUJITA Tomonori 		break;
2880639db475SFUJITA Tomonori 	case SYNCHRONIZE_CACHE:
2881639db475SFUJITA Tomonori 		delay_override = 1;
2882639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
2883639db475SFUJITA Tomonori 		break;
2884639db475SFUJITA Tomonori 	case WRITE_BUFFER:
2885639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2886639db475SFUJITA Tomonori 		break;
2887639db475SFUJITA Tomonori 	case XDWRITEREAD_10:
2888639db475SFUJITA Tomonori 		if (!scsi_bidi_cmnd(SCpnt)) {
2889639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
2890639db475SFUJITA Tomonori 					INVALID_FIELD_IN_CDB, 0);
2891639db475SFUJITA Tomonori 			errsts = check_condition_result;
2892639db475SFUJITA Tomonori 			break;
2893639db475SFUJITA Tomonori 		}
2894639db475SFUJITA Tomonori 
2895639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
2896639db475SFUJITA Tomonori 		if (errsts)
2897639db475SFUJITA Tomonori 			break;
2898639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
2899639db475SFUJITA Tomonori 			break;
2900639db475SFUJITA Tomonori 		get_data_transfer_info(cmd, &lba, &num);
2901639db475SFUJITA Tomonori 		errsts = resp_read(SCpnt, lba, num, devip);
2902639db475SFUJITA Tomonori 		if (errsts)
2903639db475SFUJITA Tomonori 			break;
2904639db475SFUJITA Tomonori 		errsts = resp_write(SCpnt, lba, num, devip);
2905639db475SFUJITA Tomonori 		if (errsts)
2906639db475SFUJITA Tomonori 			break;
2907639db475SFUJITA Tomonori 		errsts = resp_xdwriteread(SCpnt, lba, num, devip);
2908639db475SFUJITA Tomonori 		break;
2909639db475SFUJITA Tomonori 	default:
2910639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2911639db475SFUJITA Tomonori 			printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
2912639db475SFUJITA Tomonori 			       "supported\n", *cmd);
2913639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2914639db475SFUJITA Tomonori 		if (errsts)
2915639db475SFUJITA Tomonori 			break;	/* Unit attention takes precedence */
2916639db475SFUJITA Tomonori 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
2917639db475SFUJITA Tomonori 		errsts = check_condition_result;
2918639db475SFUJITA Tomonori 		break;
2919639db475SFUJITA Tomonori 	}
2920639db475SFUJITA Tomonori 	return schedule_resp(SCpnt, devip, done, errsts,
2921639db475SFUJITA Tomonori 			     (delay_override ? 0 : scsi_debug_delay));
2922639db475SFUJITA Tomonori }
2923639db475SFUJITA Tomonori 
29249e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
29259e603ca0SFUJITA Tomonori 	.proc_info =		scsi_debug_proc_info,
29269e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
29279e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
29289e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
29299e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
29309e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
29319e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
29329e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
29339e603ca0SFUJITA Tomonori 	.queuecommand =		scsi_debug_queuecommand,
29349e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
29359e603ca0SFUJITA Tomonori 	.eh_bus_reset_handler = scsi_debug_bus_reset,
29369e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
29379e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
29389e603ca0SFUJITA Tomonori 	.bios_param =		scsi_debug_biosparam,
29399e603ca0SFUJITA Tomonori 	.can_queue =		SCSI_DEBUG_CANQUEUE,
29409e603ca0SFUJITA Tomonori 	.this_id =		7,
29419e603ca0SFUJITA Tomonori 	.sg_tablesize =		256,
29429e603ca0SFUJITA Tomonori 	.cmd_per_lun =		16,
29439e603ca0SFUJITA Tomonori 	.max_sectors =		0xffff,
29449e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
29459e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
29469e603ca0SFUJITA Tomonori };
29479e603ca0SFUJITA Tomonori 
29481da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev)
29491da177e4SLinus Torvalds {
29501da177e4SLinus Torvalds         int error = 0;
29511da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
29521da177e4SLinus Torvalds         struct Scsi_Host *hpnt;
29531da177e4SLinus Torvalds 
29541da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
29551da177e4SLinus Torvalds 
29561da177e4SLinus Torvalds         hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
29571da177e4SLinus Torvalds         if (NULL == hpnt) {
29581da177e4SLinus Torvalds                 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
29591da177e4SLinus Torvalds                 error = -ENODEV;
29601da177e4SLinus Torvalds 		return error;
29611da177e4SLinus Torvalds         }
29621da177e4SLinus Torvalds 
29631da177e4SLinus Torvalds         sdbg_host->shost = hpnt;
29641da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
29651da177e4SLinus Torvalds 	if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
29661da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts + 1;
29671da177e4SLinus Torvalds 	else
29681da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts;
2969c65b1445SDouglas Gilbert 	hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;	/* = scsi_debug_max_luns; */
29701da177e4SLinus Torvalds 
29711da177e4SLinus Torvalds         error = scsi_add_host(hpnt, &sdbg_host->dev);
29721da177e4SLinus Torvalds         if (error) {
29731da177e4SLinus Torvalds                 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
29741da177e4SLinus Torvalds                 error = -ENODEV;
29751da177e4SLinus Torvalds 		scsi_host_put(hpnt);
29761da177e4SLinus Torvalds         } else
29771da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
29781da177e4SLinus Torvalds 
29791da177e4SLinus Torvalds 
29801da177e4SLinus Torvalds         return error;
29811da177e4SLinus Torvalds }
29821da177e4SLinus Torvalds 
29831da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev)
29841da177e4SLinus Torvalds {
29851da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
29868b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
29871da177e4SLinus Torvalds 
29881da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
29891da177e4SLinus Torvalds 
29901da177e4SLinus Torvalds 	if (!sdbg_host) {
29911da177e4SLinus Torvalds 		printk(KERN_ERR "%s: Unable to locate host info\n",
29921da177e4SLinus Torvalds 		       __FUNCTION__);
29931da177e4SLinus Torvalds 		return -ENODEV;
29941da177e4SLinus Torvalds 	}
29951da177e4SLinus Torvalds 
29961da177e4SLinus Torvalds         scsi_remove_host(sdbg_host->shost);
29971da177e4SLinus Torvalds 
29988b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
29998b40228fSFUJITA Tomonori 				 dev_list) {
30001da177e4SLinus Torvalds                 list_del(&sdbg_devinfo->dev_list);
30011da177e4SLinus Torvalds                 kfree(sdbg_devinfo);
30021da177e4SLinus Torvalds         }
30031da177e4SLinus Torvalds 
30041da177e4SLinus Torvalds         scsi_host_put(sdbg_host->shost);
30051da177e4SLinus Torvalds         return 0;
30061da177e4SLinus Torvalds }
30071da177e4SLinus Torvalds 
30088dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
30098dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
30101da177e4SLinus Torvalds {
30118dea0d02SFUJITA Tomonori 	return 1;
30128dea0d02SFUJITA Tomonori }
30131da177e4SLinus Torvalds 
30148dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
30158dea0d02SFUJITA Tomonori 	.name = "pseudo",
30168dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
30178dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
30188dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
30198dea0d02SFUJITA Tomonori };
3020