xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision eac6e8e4)
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
97597136abSMartin K. Petersen #define DEF_SECTOR_SIZE 512
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */
1001da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE   1
1011da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR   2
1021da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT   4
1031da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR   8
1046f3cbf55SDouglas Gilbert #define SCSI_DEBUG_OPT_TRANSPORT_ERR   16
1051da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
1061da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1071da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1081da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1096f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1106f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1111da177e4SLinus Torvalds  *
1121da177e4SLinus Torvalds  * When "every_nth" < 0 then after "- every_nth" commands:
1131da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1141da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1151da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1166f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1176f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1181da177e4SLinus Torvalds  * This will continue until some other action occurs (e.g. the user
1191da177e4SLinus Torvalds  * writing a new value (other than -1 or 1) to every_nth via sysfs).
1201da177e4SLinus Torvalds  */
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
1231da177e4SLinus Torvalds  * sector on read commands: */
1241da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
1251da177e4SLinus Torvalds 
1261da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
1271da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
1281da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
129c65b1445SDouglas Gilbert #define SAM2_WLUN_REPORT_LUNS 0xc101
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST;
1321da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY;
1331da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
1341da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH;
1351da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS;
1361da177e4SLinus Torvalds static int scsi_debug_num_parts = DEF_NUM_PARTS;
1371da177e4SLinus Torvalds static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
1381da177e4SLinus Torvalds static int scsi_debug_opts = DEF_OPTS;
1391da177e4SLinus Torvalds static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
1401da177e4SLinus Torvalds static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
1411da177e4SLinus Torvalds static int scsi_debug_dsense = DEF_D_SENSE;
142c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
143c65b1445SDouglas Gilbert static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
14423183910SDouglas Gilbert static int scsi_debug_fake_rw = DEF_FAKE_RW;
14523183910SDouglas Gilbert static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
146597136abSMartin K. Petersen static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds static int scsi_debug_cmnd_count = 0;
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds #define DEV_READONLY(TGT)      (0)
1511da177e4SLinus Torvalds #define DEV_REMOVEABLE(TGT)    (0)
1521da177e4SLinus Torvalds 
153c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
1541da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
1571da177e4SLinus Torvalds    may still need them */
1581da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
1591da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
1601da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds #define SDEBUG_SENSE_LEN 32
1651da177e4SLinus Torvalds 
1669e603ca0SFUJITA Tomonori #define SCSI_DEBUG_CANQUEUE  255
1679e603ca0SFUJITA Tomonori #define SCSI_DEBUG_MAX_CMD_LEN 16
1689e603ca0SFUJITA Tomonori 
1691da177e4SLinus Torvalds struct sdebug_dev_info {
1701da177e4SLinus Torvalds 	struct list_head dev_list;
1711da177e4SLinus Torvalds 	unsigned char sense_buff[SDEBUG_SENSE_LEN];	/* weak nexus */
1721da177e4SLinus Torvalds 	unsigned int channel;
1731da177e4SLinus Torvalds 	unsigned int target;
1741da177e4SLinus Torvalds 	unsigned int lun;
1751da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
176c65b1445SDouglas Gilbert 	unsigned int wlun;
1771da177e4SLinus Torvalds 	char reset;
178c65b1445SDouglas Gilbert 	char stopped;
1791da177e4SLinus Torvalds 	char used;
1801da177e4SLinus Torvalds };
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds struct sdebug_host_info {
1831da177e4SLinus Torvalds 	struct list_head host_list;
1841da177e4SLinus Torvalds 	struct Scsi_Host *shost;
1851da177e4SLinus Torvalds 	struct device dev;
1861da177e4SLinus Torvalds 	struct list_head dev_info_list;
1871da177e4SLinus Torvalds };
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds #define to_sdebug_host(d)	\
1901da177e4SLinus Torvalds 	container_of(d, struct sdebug_host_info, dev)
1911da177e4SLinus Torvalds 
1921da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
1931da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
1941da177e4SLinus Torvalds 
1951da177e4SLinus Torvalds typedef void (* done_funct_t) (struct scsi_cmnd *);
1961da177e4SLinus Torvalds 
1971da177e4SLinus Torvalds struct sdebug_queued_cmd {
1981da177e4SLinus Torvalds 	int in_use;
1991da177e4SLinus Torvalds 	struct timer_list cmnd_timer;
2001da177e4SLinus Torvalds 	done_funct_t done_funct;
2011da177e4SLinus Torvalds 	struct scsi_cmnd * a_cmnd;
2021da177e4SLinus Torvalds 	int scsi_result;
2031da177e4SLinus Torvalds };
2041da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
2051da177e4SLinus Torvalds 
2061da177e4SLinus Torvalds static unsigned char * fake_storep;	/* ramdisk storage */
2071da177e4SLinus Torvalds 
2081da177e4SLinus Torvalds static int num_aborts = 0;
2091da177e4SLinus Torvalds static int num_dev_resets = 0;
2101da177e4SLinus Torvalds static int num_bus_resets = 0;
2111da177e4SLinus Torvalds static int num_host_resets = 0;
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock);
2141da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
2151da177e4SLinus Torvalds 
2161da177e4SLinus Torvalds static char sdebug_proc_name[] = "scsi_debug";
2171da177e4SLinus Torvalds 
2181da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
2191da177e4SLinus Torvalds 
2201da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
2211da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
2221da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
2231da177e4SLinus Torvalds };
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds static const int check_condition_result =
2261da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
2271da177e4SLinus Torvalds 
228c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
229c65b1445SDouglas Gilbert 				    0, 0, 0x2, 0x4b};
230c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
231c65b1445SDouglas Gilbert 			           0, 0, 0x0, 0x0};
232c65b1445SDouglas Gilbert 
2331da177e4SLinus Torvalds static int sdebug_add_adapter(void);
2341da177e4SLinus Torvalds static void sdebug_remove_adapter(void);
2351da177e4SLinus Torvalds 
2368dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
2378dea0d02SFUJITA Tomonori {
2388dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
2398dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
2408dea0d02SFUJITA Tomonori 
2418dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
2428dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2438dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
2448dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
2458dea0d02SFUJITA Tomonori 		    (scsi_debug_num_tgts > hpnt->this_id))
2468dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts + 1;
2478dea0d02SFUJITA Tomonori 		else
2488dea0d02SFUJITA Tomonori 			hpnt->max_id = scsi_debug_num_tgts;
2498dea0d02SFUJITA Tomonori 		/* scsi_debug_max_luns; */
2508dea0d02SFUJITA Tomonori 		hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
2518dea0d02SFUJITA Tomonori 	}
2528dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
2538dea0d02SFUJITA Tomonori }
2548dea0d02SFUJITA Tomonori 
2558dea0d02SFUJITA Tomonori static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
2568dea0d02SFUJITA Tomonori 			    int asc, int asq)
2578dea0d02SFUJITA Tomonori {
2588dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
2598dea0d02SFUJITA Tomonori 
2608dea0d02SFUJITA Tomonori 	sbuff = devip->sense_buff;
2618dea0d02SFUJITA Tomonori 	memset(sbuff, 0, SDEBUG_SENSE_LEN);
2628dea0d02SFUJITA Tomonori 
2638dea0d02SFUJITA Tomonori 	scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
2648dea0d02SFUJITA Tomonori 
2658dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2668dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug:    [sense_key,asc,ascq]: "
2678dea0d02SFUJITA Tomonori 		      "[0x%x,0x%x,0x%x]\n", key, asc, asq);
2688dea0d02SFUJITA Tomonori }
2691da177e4SLinus Torvalds 
2703de9f944SFUJITA Tomonori static void get_data_transfer_info(unsigned char *cmd,
2713de9f944SFUJITA Tomonori 				   unsigned long long *lba, unsigned int *num)
2723de9f944SFUJITA Tomonori {
2733de9f944SFUJITA Tomonori 	switch (*cmd) {
2743de9f944SFUJITA Tomonori 	case WRITE_16:
2753de9f944SFUJITA Tomonori 	case READ_16:
276d5cdc989SFUJITA Tomonori 		*lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
277d5cdc989SFUJITA Tomonori 			(u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
278d5cdc989SFUJITA Tomonori 			(u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
279d5cdc989SFUJITA Tomonori 			(u64)cmd[3] << 48 | (u64)cmd[2] << 56;
280d5cdc989SFUJITA Tomonori 
281d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
282d5cdc989SFUJITA Tomonori 			(u32)cmd[10] << 24;
2833de9f944SFUJITA Tomonori 		break;
2843de9f944SFUJITA Tomonori 	case WRITE_12:
2853de9f944SFUJITA Tomonori 	case READ_12:
286d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
287d5cdc989SFUJITA Tomonori 			(u32)cmd[2] << 24;
288d5cdc989SFUJITA Tomonori 
289d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
290d5cdc989SFUJITA Tomonori 			(u32)cmd[6] << 24;
2913de9f944SFUJITA Tomonori 		break;
2923de9f944SFUJITA Tomonori 	case WRITE_10:
2933de9f944SFUJITA Tomonori 	case READ_10:
294c639d14eSFUJITA Tomonori 	case XDWRITEREAD_10:
295d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[5] | (u32)cmd[4] << 8 |	(u32)cmd[3] << 16 |
296d5cdc989SFUJITA Tomonori 			(u32)cmd[2] << 24;
297d5cdc989SFUJITA Tomonori 
298d5cdc989SFUJITA Tomonori 		*num = (u32)cmd[8] | (u32)cmd[7] << 8;
2993de9f944SFUJITA Tomonori 		break;
3003de9f944SFUJITA Tomonori 	case WRITE_6:
3013de9f944SFUJITA Tomonori 	case READ_6:
302d5cdc989SFUJITA Tomonori 		*lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
303d5cdc989SFUJITA Tomonori 			(u32)(cmd[1] & 0x1f) << 16;
3043de9f944SFUJITA Tomonori 		*num = (0 == cmd[4]) ? 256 : cmd[4];
3053de9f944SFUJITA Tomonori 		break;
3063de9f944SFUJITA Tomonori 	default:
3073de9f944SFUJITA Tomonori 		break;
3083de9f944SFUJITA Tomonori 	}
3093de9f944SFUJITA Tomonori }
3101da177e4SLinus Torvalds 
3111da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
3121da177e4SLinus Torvalds {
3131da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
3141da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
3151da177e4SLinus Torvalds 	}
3161da177e4SLinus Torvalds 	return -EINVAL;
3171da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
3181da177e4SLinus Torvalds }
3191da177e4SLinus Torvalds 
320c65b1445SDouglas Gilbert static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
321c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
3221da177e4SLinus Torvalds {
3231da177e4SLinus Torvalds 	if (devip->reset) {
3241da177e4SLinus Torvalds 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3251da177e4SLinus Torvalds 			printk(KERN_INFO "scsi_debug: Reporting Unit "
3261da177e4SLinus Torvalds 			       "attention: power on reset\n");
3271da177e4SLinus Torvalds 		devip->reset = 0;
3281da177e4SLinus Torvalds 		mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
3291da177e4SLinus Torvalds 		return check_condition_result;
3301da177e4SLinus Torvalds 	}
331c65b1445SDouglas Gilbert 	if ((0 == reset_only) && devip->stopped) {
332c65b1445SDouglas Gilbert 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
333c65b1445SDouglas Gilbert 			printk(KERN_INFO "scsi_debug: Reporting Not "
334c65b1445SDouglas Gilbert 			       "ready: initializing command required\n");
335c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
336c65b1445SDouglas Gilbert 				0x2);
337c65b1445SDouglas Gilbert 		return check_condition_result;
338c65b1445SDouglas Gilbert 	}
3391da177e4SLinus Torvalds 	return 0;
3401da177e4SLinus Torvalds }
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
3431da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
3441da177e4SLinus Torvalds 				int arr_len)
3451da177e4SLinus Torvalds {
34621a61829SFUJITA Tomonori 	int act_len;
347072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
3481da177e4SLinus Torvalds 
349072d0bb3SFUJITA Tomonori 	if (!sdb->length)
3501da177e4SLinus Torvalds 		return 0;
351072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
3521da177e4SLinus Torvalds 		return (DID_ERROR << 16);
35321a61829SFUJITA Tomonori 
35421a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
35521a61829SFUJITA Tomonori 				      arr, arr_len);
356072d0bb3SFUJITA Tomonori 	if (sdb->resid)
357072d0bb3SFUJITA Tomonori 		sdb->resid -= act_len;
358c65b1445SDouglas Gilbert 	else
35921a61829SFUJITA Tomonori 		sdb->resid = scsi_bufflen(scp) - act_len;
36021a61829SFUJITA Tomonori 
3611da177e4SLinus Torvalds 	return 0;
3621da177e4SLinus Torvalds }
3631da177e4SLinus Torvalds 
3641da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */
3651da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
36621a61829SFUJITA Tomonori 			       int arr_len)
3671da177e4SLinus Torvalds {
36821a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
3691da177e4SLinus Torvalds 		return 0;
370072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
3711da177e4SLinus Torvalds 		return -1;
37221a61829SFUJITA Tomonori 
37321a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
3741da177e4SLinus Torvalds }
3751da177e4SLinus Torvalds 
3761da177e4SLinus Torvalds 
3771da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux   ";
3781da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug      ";
3791da177e4SLinus Torvalds static const char * inq_product_rev = "0004";
3801da177e4SLinus Torvalds 
3815a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
3825a09e398SHannes Reinecke 			   int target_dev_id, int dev_id_num,
3835a09e398SHannes Reinecke 			   const char * dev_id_str,
384c65b1445SDouglas Gilbert 			   int dev_id_str_len)
3851da177e4SLinus Torvalds {
386c65b1445SDouglas Gilbert 	int num, port_a;
387c65b1445SDouglas Gilbert 	char b[32];
3881da177e4SLinus Torvalds 
389c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
3901da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
3911da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
3921da177e4SLinus Torvalds 	arr[1] = 0x1;
3931da177e4SLinus Torvalds 	arr[2] = 0x0;
3941da177e4SLinus Torvalds 	memcpy(&arr[4], inq_vendor_id, 8);
3951da177e4SLinus Torvalds 	memcpy(&arr[12], inq_product_id, 16);
3961da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
3971da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
3981da177e4SLinus Torvalds 	arr[3] = num;
3991da177e4SLinus Torvalds 	num += 4;
400c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
401c65b1445SDouglas Gilbert 		/* NAA-5, Logical unit identifier (binary) */
402c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* binary (not necessarily sas) */
403c65b1445SDouglas Gilbert 		arr[num++] = 0x3;	/* PIV=0, lu, naa */
404c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
405c65b1445SDouglas Gilbert 		arr[num++] = 0x8;
406c65b1445SDouglas Gilbert 		arr[num++] = 0x53;  /* naa-5 ieee company id=0x333333 (fake) */
407c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
408c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
409c65b1445SDouglas Gilbert 		arr[num++] = 0x30;
410c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 24);
411c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 16) & 0xff;
412c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 8) & 0xff;
413c65b1445SDouglas Gilbert 		arr[num++] = dev_id_num & 0xff;
414c65b1445SDouglas Gilbert 		/* Target relative port number */
415c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
416c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
417c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
418c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
419c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
420c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
421c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
422c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
423c65b1445SDouglas Gilbert 	}
424c65b1445SDouglas Gilbert 	/* NAA-5, Target port identifier */
425c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
426c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
427c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
428c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
429c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
430c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
431c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
432c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
433c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
434c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
435c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
436c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
4375a09e398SHannes Reinecke 	/* NAA-5, Target port group identifier */
4385a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
4395a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
4405a09e398SHannes Reinecke 	arr[num++] = 0x0;
4415a09e398SHannes Reinecke 	arr[num++] = 0x4;
4425a09e398SHannes Reinecke 	arr[num++] = 0;
4435a09e398SHannes Reinecke 	arr[num++] = 0;
4445a09e398SHannes Reinecke 	arr[num++] = (port_group_id >> 8) & 0xff;
4455a09e398SHannes Reinecke 	arr[num++] = port_group_id & 0xff;
446c65b1445SDouglas Gilbert 	/* NAA-5, Target device identifier */
447c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
448c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
449c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
450c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
451c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
452c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
453c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
454c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
455c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 24);
456c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 16) & 0xff;
457c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 8) & 0xff;
458c65b1445SDouglas Gilbert 	arr[num++] = target_dev_id & 0xff;
459c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
460c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
461c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
462c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
463c65b1445SDouglas Gilbert 	arr[num++] = 24;
464c65b1445SDouglas Gilbert 	memcpy(arr + num, "naa.52222220", 12);
465c65b1445SDouglas Gilbert 	num += 12;
466c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
467c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
468c65b1445SDouglas Gilbert 	num += 8;
469c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
470c65b1445SDouglas Gilbert 	num += 4;
471c65b1445SDouglas Gilbert 	return num;
472c65b1445SDouglas Gilbert }
473c65b1445SDouglas Gilbert 
474c65b1445SDouglas Gilbert 
475c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
476c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
477c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
478c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
479c65b1445SDouglas Gilbert };
480c65b1445SDouglas Gilbert 
481c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr)
482c65b1445SDouglas Gilbert {
483c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
484c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
485c65b1445SDouglas Gilbert }
486c65b1445SDouglas Gilbert 
487c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr)
488c65b1445SDouglas Gilbert {
489c65b1445SDouglas Gilbert 	int num = 0;
490c65b1445SDouglas Gilbert 	const char * na1 = "https://www.kernel.org/config";
491c65b1445SDouglas Gilbert 	const char * na2 = "http://www.kernel.org/log";
492c65b1445SDouglas Gilbert 	int plen, olen;
493c65b1445SDouglas Gilbert 
494c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
495c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
496c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
497c65b1445SDouglas Gilbert 	olen = strlen(na1);
498c65b1445SDouglas Gilbert 	plen = olen + 1;
499c65b1445SDouglas Gilbert 	if (plen % 4)
500c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
501c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
502c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
503c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
504c65b1445SDouglas Gilbert 	num += plen;
505c65b1445SDouglas Gilbert 
506c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
507c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
508c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
509c65b1445SDouglas Gilbert 	olen = strlen(na2);
510c65b1445SDouglas Gilbert 	plen = olen + 1;
511c65b1445SDouglas Gilbert 	if (plen % 4)
512c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
513c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
514c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
515c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
516c65b1445SDouglas Gilbert 	num += plen;
517c65b1445SDouglas Gilbert 
518c65b1445SDouglas Gilbert 	return num;
519c65b1445SDouglas Gilbert }
520c65b1445SDouglas Gilbert 
521c65b1445SDouglas Gilbert /* SCSI ports VPD page */
522c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
523c65b1445SDouglas Gilbert {
524c65b1445SDouglas Gilbert 	int num = 0;
525c65b1445SDouglas Gilbert 	int port_a, port_b;
526c65b1445SDouglas Gilbert 
527c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
528c65b1445SDouglas Gilbert 	port_b = port_a + 1;
529c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
530c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
531c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
532c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
533c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
534c65b1445SDouglas Gilbert 	num += 6;
535c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
536c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
537c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
538c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
539c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
540c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
541c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
542c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
543c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
544c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
545c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
546c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
547c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
548c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
549c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
550c65b1445SDouglas Gilbert 
551c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
552c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
553c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
554c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
555c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
556c65b1445SDouglas Gilbert 	num += 6;
557c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
558c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
559c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
560c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
561c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
562c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
563c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
564c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
565c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
566c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
567c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
568c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 24);
569c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 16) & 0xff;
570c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 8) & 0xff;
571c65b1445SDouglas Gilbert 	arr[num++] = port_b & 0xff;
572c65b1445SDouglas Gilbert 
573c65b1445SDouglas Gilbert 	return num;
574c65b1445SDouglas Gilbert }
575c65b1445SDouglas Gilbert 
576c65b1445SDouglas Gilbert 
577c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
578c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
579c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
580c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
581c65b1445SDouglas Gilbert '1','2','3','4',
582c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
583c65b1445SDouglas Gilbert 0xec,0,0,0,
584c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
585c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
586c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
587c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
588c65b1445SDouglas Gilbert 0x53,0x41,
589c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
590c65b1445SDouglas Gilbert 0x20,0x20,
591c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
592c65b1445SDouglas Gilbert 0x10,0x80,
593c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
594c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
595c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
596c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
597c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
598c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
599c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
600c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
601c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
602c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
603c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
604c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
605c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
606c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
607c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
608c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
609c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0xa5,0x51,
619c65b1445SDouglas Gilbert };
620c65b1445SDouglas Gilbert 
621c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr)
622c65b1445SDouglas Gilbert {
623c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
624c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
625c65b1445SDouglas Gilbert }
626c65b1445SDouglas Gilbert 
627c65b1445SDouglas Gilbert 
628c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
629c65b1445SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4,
630c65b1445SDouglas Gilbert 	0,0,0x4,0,
631c65b1445SDouglas Gilbert 	0,0,0,64,
632c65b1445SDouglas Gilbert };
633c65b1445SDouglas Gilbert 
634c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr)
635c65b1445SDouglas Gilbert {
636c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
637c65b1445SDouglas Gilbert 	if (sdebug_store_sectors > 0x400) {
638c65b1445SDouglas Gilbert 		arr[4] = (sdebug_store_sectors >> 24) & 0xff;
639c65b1445SDouglas Gilbert 		arr[5] = (sdebug_store_sectors >> 16) & 0xff;
640c65b1445SDouglas Gilbert 		arr[6] = (sdebug_store_sectors >> 8) & 0xff;
641c65b1445SDouglas Gilbert 		arr[7] = sdebug_store_sectors & 0xff;
642c65b1445SDouglas Gilbert 	}
643c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
6441da177e4SLinus Torvalds }
6451da177e4SLinus Torvalds 
646eac6e8e4SMatthew Wilcox static int inquiry_evpd_b1(unsigned char *arr)
647eac6e8e4SMatthew Wilcox {
648eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
649eac6e8e4SMatthew Wilcox 	arr[0] = 0;
650eac6e8e4SMatthew Wilcox 	arr[1] = 1;
651eac6e8e4SMatthew Wilcox 
652eac6e8e4SMatthew Wilcox 	return 0x3c;
653eac6e8e4SMatthew Wilcox }
6541da177e4SLinus Torvalds 
6551da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
656c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
6571da177e4SLinus Torvalds 
6581da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd * scp, int target,
6591da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
6601da177e4SLinus Torvalds {
6611da177e4SLinus Torvalds 	unsigned char pq_pdt;
6625a09e398SHannes Reinecke 	unsigned char * arr;
6631da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
6645a09e398SHannes Reinecke 	int alloc_len, n, ret;
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds 	alloc_len = (cmd[3] << 8) + cmd[4];
6676f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
6686f3cbf55SDouglas Gilbert 	if (! arr)
6696f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
670c65b1445SDouglas Gilbert 	if (devip->wlun)
671c65b1445SDouglas Gilbert 		pq_pdt = 0x1e;	/* present, wlun */
672c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (0 == devip->lun))
673c65b1445SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, no device type */
674c65b1445SDouglas Gilbert 	else
6751da177e4SLinus Torvalds 		pq_pdt = (scsi_debug_ptype & 0x1f);
6761da177e4SLinus Torvalds 	arr[0] = pq_pdt;
6771da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
6781da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
6791da177e4SLinus Torvalds 			       	0);
6805a09e398SHannes Reinecke 		kfree(arr);
6811da177e4SLinus Torvalds 		return check_condition_result;
6821da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
6835a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
684c65b1445SDouglas Gilbert 		char lu_id_str[6];
685c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
6861da177e4SLinus Torvalds 
6875a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
6885a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
68923183910SDouglas Gilbert 		if (0 == scsi_debug_vpd_use_hostno)
69023183910SDouglas Gilbert 			host_no = 0;
691c65b1445SDouglas Gilbert 		lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
692c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
693c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
694c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
695c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
6961da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
697c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
698c65b1445SDouglas Gilbert 			n = 4;
699c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
700c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
701c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
702c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
703c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
704c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
705c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
706c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
707c65b1445SDouglas Gilbert 			arr[n++] = 0x89;  /* ATA information */
708c65b1445SDouglas Gilbert 			arr[n++] = 0xb0;  /* Block limits (SBC) */
709eac6e8e4SMatthew Wilcox 			arr[n++] = 0xb1;  /* Block characteristics (SBC) */
710c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
7111da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
712c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
7131da177e4SLinus Torvalds 			arr[3] = len;
714c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
7151da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
716c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
7175a09e398SHannes Reinecke 			arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
7185a09e398SHannes Reinecke 						 target_dev_id, lu_id_num,
7195a09e398SHannes Reinecke 						 lu_id_str, len);
720c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
721c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
722c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_84(&arr[4]);
723c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
724c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
725c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_85(&arr[4]);
726c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
727c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
728c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
729c65b1445SDouglas Gilbert 			arr[4] = 0x0;   /* no protection stuff */
730c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
731c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
732c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
733c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
734c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
735c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
736c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
737c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
738c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
739c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
740c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
741c65b1445SDouglas Gilbert 		} else if (0x89 == cmd[2]) { /* ATA information */
742c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
743c65b1445SDouglas Gilbert 			n = inquiry_evpd_89(&arr[4]);
744c65b1445SDouglas Gilbert 			arr[2] = (n >> 8);
745c65b1445SDouglas Gilbert 			arr[3] = (n & 0xff);
746c65b1445SDouglas Gilbert 		} else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
747c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
748c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_b0(&arr[4]);
749eac6e8e4SMatthew Wilcox 		} else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
750eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
751eac6e8e4SMatthew Wilcox 			arr[3] = inquiry_evpd_b1(&arr[4]);
7521da177e4SLinus Torvalds 		} else {
7531da177e4SLinus Torvalds 			/* Illegal request, invalid field in cdb */
7541da177e4SLinus Torvalds 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
7551da177e4SLinus Torvalds 					INVALID_FIELD_IN_CDB, 0);
7565a09e398SHannes Reinecke 			kfree(arr);
7571da177e4SLinus Torvalds 			return check_condition_result;
7581da177e4SLinus Torvalds 		}
759c65b1445SDouglas Gilbert 		len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
7605a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
761c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
7625a09e398SHannes Reinecke 		kfree(arr);
7635a09e398SHannes Reinecke 		return ret;
7641da177e4SLinus Torvalds 	}
7651da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
7661da177e4SLinus Torvalds 	arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0;	/* Removable disk */
7671da177e4SLinus Torvalds 	arr[2] = scsi_debug_scsi_level;
7681da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
7691da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
7705a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno)
7715a09e398SHannes Reinecke 		arr[5] = 0x10; /* claim: implicit TGPS */
772c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
7731da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
774c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
7751da177e4SLinus Torvalds 	memcpy(&arr[8], inq_vendor_id, 8);
7761da177e4SLinus Torvalds 	memcpy(&arr[16], inq_product_id, 16);
7771da177e4SLinus Torvalds 	memcpy(&arr[32], inq_product_rev, 4);
7781da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
779c65b1445SDouglas Gilbert 	arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
780c65b1445SDouglas Gilbert 	arr[60] = 0x3; arr[61] = 0x14;  /* SPC-3 ANSI */
781c65b1445SDouglas Gilbert 	n = 62;
7821da177e4SLinus Torvalds 	if (scsi_debug_ptype == 0) {
783c65b1445SDouglas Gilbert 		arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
7841da177e4SLinus Torvalds 	} else if (scsi_debug_ptype == 1) {
785c65b1445SDouglas Gilbert 		arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
7861da177e4SLinus Torvalds 	}
787c65b1445SDouglas Gilbert 	arr[n++] = 0xc; arr[n++] = 0xf;  /* SAS-1.1 rev 10 */
7885a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
7891da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
7905a09e398SHannes Reinecke 	kfree(arr);
7915a09e398SHannes Reinecke 	return ret;
7921da177e4SLinus Torvalds }
7931da177e4SLinus Torvalds 
7941da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp,
7951da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip)
7961da177e4SLinus Torvalds {
7971da177e4SLinus Torvalds 	unsigned char * sbuff;
7981da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
7991da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_SENSE_LEN];
800c65b1445SDouglas Gilbert 	int want_dsense;
8011da177e4SLinus Torvalds 	int len = 18;
8021da177e4SLinus Torvalds 
803c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
8041da177e4SLinus Torvalds 	if (devip->reset == 1)
805c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
806c65b1445SDouglas Gilbert 	want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
8071da177e4SLinus Torvalds 	sbuff = devip->sense_buff;
808c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
809c65b1445SDouglas Gilbert 		if (want_dsense) {
810c65b1445SDouglas Gilbert 			arr[0] = 0x72;
811c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
812c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
813c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
814c65b1445SDouglas Gilbert 		} else {
815c65b1445SDouglas Gilbert 			arr[0] = 0x70;
816c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
817c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
818c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
819c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
820c65b1445SDouglas Gilbert 		}
821c65b1445SDouglas Gilbert 	} else {
822c65b1445SDouglas Gilbert 		memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
8231da177e4SLinus Torvalds 		if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
8241da177e4SLinus Torvalds 			/* DESC bit set and sense_buff in fixed format */
825c65b1445SDouglas Gilbert 			memset(arr, 0, sizeof(arr));
8261da177e4SLinus Torvalds 			arr[0] = 0x72;
8271da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
8281da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
8291da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
8301da177e4SLinus Torvalds 			len = 8;
831c65b1445SDouglas Gilbert 		}
832c65b1445SDouglas Gilbert 	}
833c65b1445SDouglas Gilbert 	mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
8341da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
8351da177e4SLinus Torvalds }
8361da177e4SLinus Torvalds 
837c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp,
838c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
839c65b1445SDouglas Gilbert {
840c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
841c65b1445SDouglas Gilbert 	int power_cond, errsts, start;
842c65b1445SDouglas Gilbert 
843c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
844c65b1445SDouglas Gilbert 		return errsts;
845c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
846c65b1445SDouglas Gilbert 	if (power_cond) {
847c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
848c65b1445SDouglas Gilbert 			       	0);
849c65b1445SDouglas Gilbert 		return check_condition_result;
850c65b1445SDouglas Gilbert 	}
851c65b1445SDouglas Gilbert 	start = cmd[4] & 1;
852c65b1445SDouglas Gilbert 	if (start == devip->stopped)
853c65b1445SDouglas Gilbert 		devip->stopped = !start;
854c65b1445SDouglas Gilbert 	return 0;
855c65b1445SDouglas Gilbert }
856c65b1445SDouglas Gilbert 
85728898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
85828898873SFUJITA Tomonori {
85928898873SFUJITA Tomonori 	if (scsi_debug_virtual_gb > 0)
86028898873SFUJITA Tomonori 		return 2048 * 1024 * scsi_debug_virtual_gb;
86128898873SFUJITA Tomonori 	else
86228898873SFUJITA Tomonori 		return sdebug_store_sectors;
86328898873SFUJITA Tomonori }
86428898873SFUJITA Tomonori 
8651da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
8661da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp,
8671da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
8681da177e4SLinus Torvalds {
8691da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
870c65b1445SDouglas Gilbert 	unsigned int capac;
8711da177e4SLinus Torvalds 	int errsts;
8721da177e4SLinus Torvalds 
873c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
8741da177e4SLinus Torvalds 		return errsts;
875c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
87628898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
8771da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
878c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
879c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
8801da177e4SLinus Torvalds 		arr[0] = (capac >> 24);
8811da177e4SLinus Torvalds 		arr[1] = (capac >> 16) & 0xff;
8821da177e4SLinus Torvalds 		arr[2] = (capac >> 8) & 0xff;
8831da177e4SLinus Torvalds 		arr[3] = capac & 0xff;
884c65b1445SDouglas Gilbert 	} else {
885c65b1445SDouglas Gilbert 		arr[0] = 0xff;
886c65b1445SDouglas Gilbert 		arr[1] = 0xff;
887c65b1445SDouglas Gilbert 		arr[2] = 0xff;
888c65b1445SDouglas Gilbert 		arr[3] = 0xff;
889c65b1445SDouglas Gilbert 	}
890597136abSMartin K. Petersen 	arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
891597136abSMartin K. Petersen 	arr[7] = scsi_debug_sector_size & 0xff;
8921da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
8931da177e4SLinus Torvalds }
8941da177e4SLinus Torvalds 
895c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
896c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp,
897c65b1445SDouglas Gilbert 			  struct sdebug_dev_info * devip)
898c65b1445SDouglas Gilbert {
899c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
900c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
901c65b1445SDouglas Gilbert 	unsigned long long capac;
902c65b1445SDouglas Gilbert 	int errsts, k, alloc_len;
903c65b1445SDouglas Gilbert 
904c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
905c65b1445SDouglas Gilbert 		return errsts;
906c65b1445SDouglas Gilbert 	alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
907c65b1445SDouglas Gilbert 		     + cmd[13]);
908c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
90928898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
910c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
911c65b1445SDouglas Gilbert 	capac = sdebug_capacity - 1;
912c65b1445SDouglas Gilbert 	for (k = 0; k < 8; ++k, capac >>= 8)
913c65b1445SDouglas Gilbert 		arr[7 - k] = capac & 0xff;
914597136abSMartin K. Petersen 	arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
915597136abSMartin K. Petersen 	arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
916597136abSMartin K. Petersen 	arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
917597136abSMartin K. Petersen 	arr[11] = scsi_debug_sector_size & 0xff;
918c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
919c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
920c65b1445SDouglas Gilbert }
921c65b1445SDouglas Gilbert 
9225a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
9235a09e398SHannes Reinecke 
9245a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp,
9255a09e398SHannes Reinecke 			      struct sdebug_dev_info * devip)
9265a09e398SHannes Reinecke {
9275a09e398SHannes Reinecke 	unsigned char *cmd = (unsigned char *)scp->cmnd;
9285a09e398SHannes Reinecke 	unsigned char * arr;
9295a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
9305a09e398SHannes Reinecke 	int n, ret, alen, rlen;
9315a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
9325a09e398SHannes Reinecke 
9335a09e398SHannes Reinecke 	alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
9345a09e398SHannes Reinecke 		+ cmd[9]);
9355a09e398SHannes Reinecke 
9366f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
9376f3cbf55SDouglas Gilbert 	if (! arr)
9386f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
9395a09e398SHannes Reinecke 	/*
9405a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
9415a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
9425a09e398SHannes Reinecke 	 * So we create two port groups with one port each
9435a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
9445a09e398SHannes Reinecke 	 */
9455a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
9465a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
9475a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
9485a09e398SHannes Reinecke 	    (devip->channel & 0x7f);
9495a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
9505a09e398SHannes Reinecke 	    (devip->channel & 0x7f) + 0x80;
9515a09e398SHannes Reinecke 
9525a09e398SHannes Reinecke 	/*
9535a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
9545a09e398SHannes Reinecke 	 */
9555a09e398SHannes Reinecke 	n = 4;
9565a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno) {
9575a09e398SHannes Reinecke 	    arr[n++] = host_no % 3; /* Asymm access state */
9585a09e398SHannes Reinecke 	    arr[n++] = 0x0F; /* claim: all states are supported */
9595a09e398SHannes Reinecke 	} else {
9605a09e398SHannes Reinecke 	    arr[n++] = 0x0; /* Active/Optimized path */
9615a09e398SHannes Reinecke 	    arr[n++] = 0x01; /* claim: only support active/optimized paths */
9625a09e398SHannes Reinecke 	}
9635a09e398SHannes Reinecke 	arr[n++] = (port_group_a >> 8) & 0xff;
9645a09e398SHannes Reinecke 	arr[n++] = port_group_a & 0xff;
9655a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
9665a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
9675a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
9685a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
9695a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
9705a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
9715a09e398SHannes Reinecke 	arr[n++] = (port_a >> 8) & 0xff;
9725a09e398SHannes Reinecke 	arr[n++] = port_a & 0xff;
9735a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
9745a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
9755a09e398SHannes Reinecke 	arr[n++] = (port_group_b >> 8) & 0xff;
9765a09e398SHannes Reinecke 	arr[n++] = port_group_b & 0xff;
9775a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
9785a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
9795a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
9805a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
9815a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
9825a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
9835a09e398SHannes Reinecke 	arr[n++] = (port_b >> 8) & 0xff;
9845a09e398SHannes Reinecke 	arr[n++] = port_b & 0xff;
9855a09e398SHannes Reinecke 
9865a09e398SHannes Reinecke 	rlen = n - 4;
9875a09e398SHannes Reinecke 	arr[0] = (rlen >> 24) & 0xff;
9885a09e398SHannes Reinecke 	arr[1] = (rlen >> 16) & 0xff;
9895a09e398SHannes Reinecke 	arr[2] = (rlen >> 8) & 0xff;
9905a09e398SHannes Reinecke 	arr[3] = rlen & 0xff;
9915a09e398SHannes Reinecke 
9925a09e398SHannes Reinecke 	/*
9935a09e398SHannes Reinecke 	 * Return the smallest value of either
9945a09e398SHannes Reinecke 	 * - The allocated length
9955a09e398SHannes Reinecke 	 * - The constructed command length
9965a09e398SHannes Reinecke 	 * - The maximum array size
9975a09e398SHannes Reinecke 	 */
9985a09e398SHannes Reinecke 	rlen = min(alen,n);
9995a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
10005a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
10015a09e398SHannes Reinecke 	kfree(arr);
10025a09e398SHannes Reinecke 	return ret;
10035a09e398SHannes Reinecke }
10045a09e398SHannes Reinecke 
10051da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
10061da177e4SLinus Torvalds 
10071da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
10081da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
10091da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
10101da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
10111da177e4SLinus Torvalds 
10121da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
10131da177e4SLinus Torvalds 	if (1 == pcontrol)
10141da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
10151da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
10161da177e4SLinus Torvalds }
10171da177e4SLinus Torvalds 
10181da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
10191da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
10201da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
10211da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
10221da177e4SLinus Torvalds 
10231da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
10241da177e4SLinus Torvalds 	if (1 == pcontrol)
10251da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
10261da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
10271da177e4SLinus Torvalds }
10281da177e4SLinus Torvalds 
10291da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target)
10301da177e4SLinus Torvalds {       /* Format device page for mode_sense */
10311da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
10321da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
10331da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
10341da177e4SLinus Torvalds 
10351da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
10361da177e4SLinus Torvalds 	p[10] = (sdebug_sectors_per >> 8) & 0xff;
10371da177e4SLinus Torvalds 	p[11] = sdebug_sectors_per & 0xff;
1038597136abSMartin K. Petersen 	p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1039597136abSMartin K. Petersen 	p[13] = scsi_debug_sector_size & 0xff;
10401da177e4SLinus Torvalds 	if (DEV_REMOVEABLE(target))
10411da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
10421da177e4SLinus Torvalds 	if (1 == pcontrol)
10431da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
10441da177e4SLinus Torvalds 	return sizeof(format_pg);
10451da177e4SLinus Torvalds }
10461da177e4SLinus Torvalds 
10471da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
10481da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
10491da177e4SLinus Torvalds 	unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
10501da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
10511da177e4SLinus Torvalds 
10521da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
10531da177e4SLinus Torvalds 	if (1 == pcontrol)
10541da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(caching_pg) - 2);
10551da177e4SLinus Torvalds 	return sizeof(caching_pg);
10561da177e4SLinus Torvalds }
10571da177e4SLinus Torvalds 
10581da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
10591da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
1060c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1061c65b1445SDouglas Gilbert 				        0, 0, 0, 0};
1062c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
10631da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
10641da177e4SLinus Torvalds 
10651da177e4SLinus Torvalds 	if (scsi_debug_dsense)
10661da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
1067c65b1445SDouglas Gilbert 	else
1068c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
10691da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
10701da177e4SLinus Torvalds 	if (1 == pcontrol)
1071c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1072c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1073c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
10741da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
10751da177e4SLinus Torvalds }
10761da177e4SLinus Torvalds 
1077c65b1445SDouglas Gilbert 
10781da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
10791da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
1080c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
10811da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
1082c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1083c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
1084c65b1445SDouglas Gilbert 
10851da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
10861da177e4SLinus Torvalds 	if (1 == pcontrol)
1087c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1088c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1089c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
10901da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
10911da177e4SLinus Torvalds }
10921da177e4SLinus Torvalds 
1093c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1094c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
1095c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1096c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1097c65b1445SDouglas Gilbert 
1098c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1099c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1100c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1101c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
1102c65b1445SDouglas Gilbert }
1103c65b1445SDouglas Gilbert 
1104c65b1445SDouglas Gilbert 
1105c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1106c65b1445SDouglas Gilbert 			      int target_dev_id)
1107c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
1108c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1109c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1110c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1111c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1112c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
1113c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1114c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1115c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1116c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1117c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1118c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
1119c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1120c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1121c65b1445SDouglas Gilbert 		};
1122c65b1445SDouglas Gilbert 	int port_a, port_b;
1123c65b1445SDouglas Gilbert 
1124c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1125c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1126c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1127c65b1445SDouglas Gilbert 	p[20] = (port_a >> 24);
1128c65b1445SDouglas Gilbert 	p[21] = (port_a >> 16) & 0xff;
1129c65b1445SDouglas Gilbert 	p[22] = (port_a >> 8) & 0xff;
1130c65b1445SDouglas Gilbert 	p[23] = port_a & 0xff;
1131c65b1445SDouglas Gilbert 	p[48 + 20] = (port_b >> 24);
1132c65b1445SDouglas Gilbert 	p[48 + 21] = (port_b >> 16) & 0xff;
1133c65b1445SDouglas Gilbert 	p[48 + 22] = (port_b >> 8) & 0xff;
1134c65b1445SDouglas Gilbert 	p[48 + 23] = port_b & 0xff;
1135c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1136c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1137c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
1138c65b1445SDouglas Gilbert }
1139c65b1445SDouglas Gilbert 
1140c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1141c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
1142c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1143c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1144c65b1445SDouglas Gilbert 		};
1145c65b1445SDouglas Gilbert 
1146c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1147c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1148c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1149c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
1150c65b1445SDouglas Gilbert }
1151c65b1445SDouglas Gilbert 
11521da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
11531da177e4SLinus Torvalds 
11541da177e4SLinus Torvalds static int resp_mode_sense(struct scsi_cmnd * scp, int target,
11551da177e4SLinus Torvalds 			   struct sdebug_dev_info * devip)
11561da177e4SLinus Torvalds {
115723183910SDouglas Gilbert 	unsigned char dbd, llbaa;
115823183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
11591da177e4SLinus Torvalds 	unsigned char dev_spec;
116023183910SDouglas Gilbert 	int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
11611da177e4SLinus Torvalds 	unsigned char * ap;
11621da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
11631da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
11641da177e4SLinus Torvalds 
1165c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
11661da177e4SLinus Torvalds 		return errsts;
116723183910SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);
11681da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
11691da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
11701da177e4SLinus Torvalds 	subpcode = cmd[3];
11711da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
117223183910SDouglas Gilbert 	llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
117323183910SDouglas Gilbert 	if ((0 == scsi_debug_ptype) && (0 == dbd))
117423183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
117523183910SDouglas Gilbert 	else
117623183910SDouglas Gilbert 		bd_len = 0;
11771da177e4SLinus Torvalds 	alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
11781da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
11791da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
11801da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
11811da177e4SLinus Torvalds 			       	0);
11821da177e4SLinus Torvalds 		return check_condition_result;
11831da177e4SLinus Torvalds 	}
1184c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1185c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
118623183910SDouglas Gilbert 	/* set DPOFUA bit for disks */
118723183910SDouglas Gilbert 	if (0 == scsi_debug_ptype)
118823183910SDouglas Gilbert 		dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
118923183910SDouglas Gilbert 	else
119023183910SDouglas Gilbert 		dev_spec = 0x0;
11911da177e4SLinus Torvalds 	if (msense_6) {
11921da177e4SLinus Torvalds 		arr[2] = dev_spec;
119323183910SDouglas Gilbert 		arr[3] = bd_len;
11941da177e4SLinus Torvalds 		offset = 4;
11951da177e4SLinus Torvalds 	} else {
11961da177e4SLinus Torvalds 		arr[3] = dev_spec;
119723183910SDouglas Gilbert 		if (16 == bd_len)
119823183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
119923183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
12001da177e4SLinus Torvalds 		offset = 8;
12011da177e4SLinus Torvalds 	}
12021da177e4SLinus Torvalds 	ap = arr + offset;
120328898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
120428898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
120528898873SFUJITA Tomonori 
120623183910SDouglas Gilbert 	if (8 == bd_len) {
120723183910SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe) {
120823183910SDouglas Gilbert 			ap[0] = 0xff;
120923183910SDouglas Gilbert 			ap[1] = 0xff;
121023183910SDouglas Gilbert 			ap[2] = 0xff;
121123183910SDouglas Gilbert 			ap[3] = 0xff;
121223183910SDouglas Gilbert 		} else {
121323183910SDouglas Gilbert 			ap[0] = (sdebug_capacity >> 24) & 0xff;
121423183910SDouglas Gilbert 			ap[1] = (sdebug_capacity >> 16) & 0xff;
121523183910SDouglas Gilbert 			ap[2] = (sdebug_capacity >> 8) & 0xff;
121623183910SDouglas Gilbert 			ap[3] = sdebug_capacity & 0xff;
121723183910SDouglas Gilbert 		}
1218597136abSMartin K. Petersen 		ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1219597136abSMartin K. Petersen 		ap[7] = scsi_debug_sector_size & 0xff;
122023183910SDouglas Gilbert 		offset += bd_len;
122123183910SDouglas Gilbert 		ap = arr + offset;
122223183910SDouglas Gilbert 	} else if (16 == bd_len) {
122323183910SDouglas Gilbert 		unsigned long long capac = sdebug_capacity;
122423183910SDouglas Gilbert 
122523183910SDouglas Gilbert         	for (k = 0; k < 8; ++k, capac >>= 8)
122623183910SDouglas Gilbert                 	ap[7 - k] = capac & 0xff;
1227597136abSMartin K. Petersen 		ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1228597136abSMartin K. Petersen 		ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1229597136abSMartin K. Petersen 		ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1230597136abSMartin K. Petersen 		ap[15] = scsi_debug_sector_size & 0xff;
123123183910SDouglas Gilbert 		offset += bd_len;
123223183910SDouglas Gilbert 		ap = arr + offset;
123323183910SDouglas Gilbert 	}
12341da177e4SLinus Torvalds 
1235c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1236c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
12371da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
12381da177e4SLinus Torvalds 			       	0);
12391da177e4SLinus Torvalds 		return check_condition_result;
12401da177e4SLinus Torvalds 	}
12411da177e4SLinus Torvalds 	switch (pcode) {
12421da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
12431da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
12441da177e4SLinus Torvalds 		offset += len;
12451da177e4SLinus Torvalds 		break;
12461da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
12471da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
12481da177e4SLinus Torvalds 		offset += len;
12491da177e4SLinus Torvalds 		break;
12501da177e4SLinus Torvalds         case 0x3:       /* Format device page, direct access */
12511da177e4SLinus Torvalds                 len = resp_format_pg(ap, pcontrol, target);
12521da177e4SLinus Torvalds                 offset += len;
12531da177e4SLinus Torvalds                 break;
12541da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
12551da177e4SLinus Torvalds 		len = resp_caching_pg(ap, pcontrol, target);
12561da177e4SLinus Torvalds 		offset += len;
12571da177e4SLinus Torvalds 		break;
12581da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
12591da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
12601da177e4SLinus Torvalds 		offset += len;
12611da177e4SLinus Torvalds 		break;
1262c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
1263c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
1264c65b1445SDouglas Gilbert 		        mk_sense_buffer(devip, ILLEGAL_REQUEST,
1265c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1266c65b1445SDouglas Gilbert 			return check_condition_result;
1267c65b1445SDouglas Gilbert 	        }
1268c65b1445SDouglas Gilbert 		len = 0;
1269c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
1270c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1271c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
1272c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1273c65b1445SDouglas Gilbert 						  target_dev_id);
1274c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
1275c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
1276c65b1445SDouglas Gilbert 		offset += len;
1277c65b1445SDouglas Gilbert 		break;
12781da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
12791da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
12801da177e4SLinus Torvalds 		offset += len;
12811da177e4SLinus Torvalds 		break;
12821da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
1283c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
12841da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
12851da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
12861da177e4SLinus Torvalds 			len += resp_format_pg(ap + len, pcontrol, target);
12871da177e4SLinus Torvalds 			len += resp_caching_pg(ap + len, pcontrol, target);
12881da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1289c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1290c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
1291c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1292c65b1445SDouglas Gilbert 						  target, target_dev_id);
1293c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
1294c65b1445SDouglas Gilbert 			}
12951da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
1296c65b1445SDouglas Gilbert 		} else {
1297c65b1445SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
1298c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1299c65b1445SDouglas Gilbert 			return check_condition_result;
1300c65b1445SDouglas Gilbert                 }
13011da177e4SLinus Torvalds 		offset += len;
13021da177e4SLinus Torvalds 		break;
13031da177e4SLinus Torvalds 	default:
13041da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
13051da177e4SLinus Torvalds 			       	0);
13061da177e4SLinus Torvalds 		return check_condition_result;
13071da177e4SLinus Torvalds 	}
13081da177e4SLinus Torvalds 	if (msense_6)
13091da177e4SLinus Torvalds 		arr[0] = offset - 1;
13101da177e4SLinus Torvalds 	else {
13111da177e4SLinus Torvalds 		arr[0] = ((offset - 2) >> 8) & 0xff;
13121da177e4SLinus Torvalds 		arr[1] = (offset - 2) & 0xff;
13131da177e4SLinus Torvalds 	}
13141da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
13151da177e4SLinus Torvalds }
13161da177e4SLinus Torvalds 
1317c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
1318c65b1445SDouglas Gilbert 
1319c65b1445SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1320c65b1445SDouglas Gilbert 			    struct sdebug_dev_info * devip)
1321c65b1445SDouglas Gilbert {
1322c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1323c65b1445SDouglas Gilbert 	int param_len, res, errsts, mpage;
1324c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1325c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1326c65b1445SDouglas Gilbert 
1327c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1328c65b1445SDouglas Gilbert 		return errsts;
1329c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1330c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
1331c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
1332c65b1445SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1333c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1334c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1335c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
1336c65b1445SDouglas Gilbert 		return check_condition_result;
1337c65b1445SDouglas Gilbert 	}
1338c65b1445SDouglas Gilbert         res = fetch_to_dev_buffer(scp, arr, param_len);
1339c65b1445SDouglas Gilbert         if (-1 == res)
1340c65b1445SDouglas Gilbert                 return (DID_ERROR << 16);
1341c65b1445SDouglas Gilbert         else if ((res < param_len) &&
1342c65b1445SDouglas Gilbert                  (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1343c65b1445SDouglas Gilbert                 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1344c65b1445SDouglas Gilbert                        " IO sent=%d bytes\n", param_len, res);
1345c65b1445SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1346c65b1445SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
134723183910SDouglas Gilbert 	if (md_len > 2) {
1348c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1349c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_PARAM_LIST, 0);
1350c65b1445SDouglas Gilbert 		return check_condition_result;
1351c65b1445SDouglas Gilbert 	}
1352c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
1353c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
1354c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
1355c65b1445SDouglas Gilbert 	if (ps) {
1356c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1357c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_PARAM_LIST, 0);
1358c65b1445SDouglas Gilbert 		return check_condition_result;
1359c65b1445SDouglas Gilbert 	}
1360c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
1361c65b1445SDouglas Gilbert 	pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1362c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
1363c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
1364c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1365c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
1366c65b1445SDouglas Gilbert 		return check_condition_result;
1367c65b1445SDouglas Gilbert 	}
1368c65b1445SDouglas Gilbert 	switch (mpage) {
1369c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
1370c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
1371c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
1372c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
1373c65b1445SDouglas Gilbert 			scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1374c65b1445SDouglas Gilbert 			return 0;
1375c65b1445SDouglas Gilbert 		}
1376c65b1445SDouglas Gilbert 		break;
1377c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
1378c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
1379c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
1380c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
1381c65b1445SDouglas Gilbert 			return 0;
1382c65b1445SDouglas Gilbert 		}
1383c65b1445SDouglas Gilbert 		break;
1384c65b1445SDouglas Gilbert 	default:
1385c65b1445SDouglas Gilbert 		break;
1386c65b1445SDouglas Gilbert 	}
1387c65b1445SDouglas Gilbert 	mk_sense_buffer(devip, ILLEGAL_REQUEST,
1388c65b1445SDouglas Gilbert 			INVALID_FIELD_IN_PARAM_LIST, 0);
1389c65b1445SDouglas Gilbert 	return check_condition_result;
1390c65b1445SDouglas Gilbert }
1391c65b1445SDouglas Gilbert 
1392c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr)
1393c65b1445SDouglas Gilbert {
1394c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1395c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
1396c65b1445SDouglas Gilbert 		};
1397c65b1445SDouglas Gilbert 
1398c65b1445SDouglas Gilbert         memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1399c65b1445SDouglas Gilbert         return sizeof(temp_l_pg);
1400c65b1445SDouglas Gilbert }
1401c65b1445SDouglas Gilbert 
1402c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr)
1403c65b1445SDouglas Gilbert {
1404c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1405c65b1445SDouglas Gilbert 		};
1406c65b1445SDouglas Gilbert 
1407c65b1445SDouglas Gilbert         memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1408c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
1409c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
1410c65b1445SDouglas Gilbert 		arr[5] = 0xff;
1411c65b1445SDouglas Gilbert 	}
1412c65b1445SDouglas Gilbert         return sizeof(ie_l_pg);
1413c65b1445SDouglas Gilbert }
1414c65b1445SDouglas Gilbert 
1415c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
1416c65b1445SDouglas Gilbert 
1417c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp,
1418c65b1445SDouglas Gilbert                           struct sdebug_dev_info * devip)
1419c65b1445SDouglas Gilbert {
142023183910SDouglas Gilbert 	int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
1421c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1422c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1423c65b1445SDouglas Gilbert 
1424c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1425c65b1445SDouglas Gilbert 		return errsts;
1426c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1427c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
1428c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
1429c65b1445SDouglas Gilbert 	if (ppc || sp) {
1430c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1431c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
1432c65b1445SDouglas Gilbert 		return check_condition_result;
1433c65b1445SDouglas Gilbert 	}
1434c65b1445SDouglas Gilbert 	pcontrol = (cmd[2] & 0xc0) >> 6;
1435c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
143623183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
1437c65b1445SDouglas Gilbert 	alloc_len = (cmd[7] << 8) + cmd[8];
1438c65b1445SDouglas Gilbert 	arr[0] = pcode;
143923183910SDouglas Gilbert 	if (0 == subpcode) {
1440c65b1445SDouglas Gilbert 		switch (pcode) {
1441c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
1442c65b1445SDouglas Gilbert 			n = 4;
1443c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
1444c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
1445c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
1446c65b1445SDouglas Gilbert 			arr[3] = n - 4;
1447c65b1445SDouglas Gilbert 			break;
1448c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
1449c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
1450c65b1445SDouglas Gilbert 			break;
1451c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
1452c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
1453c65b1445SDouglas Gilbert 			break;
1454c65b1445SDouglas Gilbert 		default:
1455c65b1445SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
1456c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1457c65b1445SDouglas Gilbert 			return check_condition_result;
1458c65b1445SDouglas Gilbert 		}
145923183910SDouglas Gilbert 	} else if (0xff == subpcode) {
146023183910SDouglas Gilbert 		arr[0] |= 0x40;
146123183910SDouglas Gilbert 		arr[1] = subpcode;
146223183910SDouglas Gilbert 		switch (pcode) {
146323183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
146423183910SDouglas Gilbert 			n = 4;
146523183910SDouglas Gilbert 			arr[n++] = 0x0;
146623183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
146723183910SDouglas Gilbert 			arr[n++] = 0x0;
146823183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
146923183910SDouglas Gilbert 			arr[n++] = 0xd;
147023183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
147123183910SDouglas Gilbert 			arr[n++] = 0x2f;
147223183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
147323183910SDouglas Gilbert 			arr[3] = n - 4;
147423183910SDouglas Gilbert 			break;
147523183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
147623183910SDouglas Gilbert 			n = 4;
147723183910SDouglas Gilbert 			arr[n++] = 0xd;
147823183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
147923183910SDouglas Gilbert 			arr[3] = n - 4;
148023183910SDouglas Gilbert 			break;
148123183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
148223183910SDouglas Gilbert 			n = 4;
148323183910SDouglas Gilbert 			arr[n++] = 0x2f;
148423183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
148523183910SDouglas Gilbert 			arr[3] = n - 4;
148623183910SDouglas Gilbert 			break;
148723183910SDouglas Gilbert 		default:
148823183910SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
148923183910SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
149023183910SDouglas Gilbert 			return check_condition_result;
149123183910SDouglas Gilbert 		}
149223183910SDouglas Gilbert 	} else {
149323183910SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
149423183910SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
149523183910SDouglas Gilbert 		return check_condition_result;
149623183910SDouglas Gilbert 	}
1497c65b1445SDouglas Gilbert 	len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1498c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1499c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
1500c65b1445SDouglas Gilbert }
1501c65b1445SDouglas Gilbert 
150219789100SFUJITA Tomonori static int check_device_access_params(struct sdebug_dev_info *devi,
150319789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
15041da177e4SLinus Torvalds {
1505c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
150619789100SFUJITA Tomonori 		mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
15071da177e4SLinus Torvalds 		return check_condition_result;
15081da177e4SLinus Torvalds 	}
1509c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
1510c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
151119789100SFUJITA Tomonori 		mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
1512c65b1445SDouglas Gilbert 		return check_condition_result;
1513c65b1445SDouglas Gilbert 	}
151419789100SFUJITA Tomonori 	return 0;
151519789100SFUJITA Tomonori }
151619789100SFUJITA Tomonori 
151719789100SFUJITA Tomonori static int do_device_access(struct scsi_cmnd *scmd,
151819789100SFUJITA Tomonori 			    struct sdebug_dev_info *devi,
151919789100SFUJITA Tomonori 			    unsigned long long lba, unsigned int num, int write)
152019789100SFUJITA Tomonori {
152119789100SFUJITA Tomonori 	int ret;
152219789100SFUJITA Tomonori 	unsigned int block, rest = 0;
152319789100SFUJITA Tomonori 	int (*func)(struct scsi_cmnd *, unsigned char *, int);
152419789100SFUJITA Tomonori 
152519789100SFUJITA Tomonori 	func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
152619789100SFUJITA Tomonori 
152719789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
152819789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
152919789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
153019789100SFUJITA Tomonori 
1531597136abSMartin K. Petersen 	ret = func(scmd, fake_storep + (block * scsi_debug_sector_size),
1532597136abSMartin K. Petersen 		   (num - rest) * scsi_debug_sector_size);
153319789100SFUJITA Tomonori 	if (!ret && rest)
1534597136abSMartin K. Petersen 		ret = func(scmd, fake_storep, rest * scsi_debug_sector_size);
153519789100SFUJITA Tomonori 
153619789100SFUJITA Tomonori 	return ret;
153719789100SFUJITA Tomonori }
153819789100SFUJITA Tomonori 
153919789100SFUJITA Tomonori static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
154019789100SFUJITA Tomonori 		     unsigned int num, struct sdebug_dev_info *devip)
154119789100SFUJITA Tomonori {
154219789100SFUJITA Tomonori 	unsigned long iflags;
154319789100SFUJITA Tomonori 	int ret;
154419789100SFUJITA Tomonori 
154519789100SFUJITA Tomonori 	ret = check_device_access_params(devip, lba, num);
154619789100SFUJITA Tomonori 	if (ret)
154719789100SFUJITA Tomonori 		return ret;
154819789100SFUJITA Tomonori 
15491da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
1550c65b1445SDouglas Gilbert 	    (lba <= OPT_MEDIUM_ERR_ADDR) &&
1551c65b1445SDouglas Gilbert 	    ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1552c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
15531da177e4SLinus Torvalds 		mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
15541da177e4SLinus Torvalds 				0);
1555c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
1556c65b1445SDouglas Gilbert 		if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1557c65b1445SDouglas Gilbert 			devip->sense_buff[0] |= 0x80;	/* Valid bit */
1558c65b1445SDouglas Gilbert 			ret = OPT_MEDIUM_ERR_ADDR;
1559c65b1445SDouglas Gilbert 			devip->sense_buff[3] = (ret >> 24) & 0xff;
1560c65b1445SDouglas Gilbert 			devip->sense_buff[4] = (ret >> 16) & 0xff;
1561c65b1445SDouglas Gilbert 			devip->sense_buff[5] = (ret >> 8) & 0xff;
1562c65b1445SDouglas Gilbert 			devip->sense_buff[6] = ret & 0xff;
1563c65b1445SDouglas Gilbert 		}
15641da177e4SLinus Torvalds 		return check_condition_result;
15651da177e4SLinus Torvalds 	}
15661da177e4SLinus Torvalds 	read_lock_irqsave(&atomic_rw, iflags);
156719789100SFUJITA Tomonori 	ret = do_device_access(SCpnt, devip, lba, num, 0);
15681da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
15691da177e4SLinus Torvalds 	return ret;
15701da177e4SLinus Torvalds }
15711da177e4SLinus Torvalds 
1572c65b1445SDouglas Gilbert static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
1573c65b1445SDouglas Gilbert 		      unsigned int num, struct sdebug_dev_info *devip)
15741da177e4SLinus Torvalds {
15751da177e4SLinus Torvalds 	unsigned long iflags;
157619789100SFUJITA Tomonori 	int ret;
15771da177e4SLinus Torvalds 
157819789100SFUJITA Tomonori 	ret = check_device_access_params(devip, lba, num);
157919789100SFUJITA Tomonori 	if (ret)
158019789100SFUJITA Tomonori 		return ret;
15811da177e4SLinus Torvalds 
15821da177e4SLinus Torvalds 	write_lock_irqsave(&atomic_rw, iflags);
158319789100SFUJITA Tomonori 	ret = do_device_access(SCpnt, devip, lba, num, 1);
15841da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
158519789100SFUJITA Tomonori 	if (-1 == ret)
15861da177e4SLinus Torvalds 		return (DID_ERROR << 16);
1587597136abSMartin K. Petersen 	else if ((ret < (num * scsi_debug_sector_size)) &&
15881da177e4SLinus Torvalds 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1589c65b1445SDouglas Gilbert 		printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
1590597136abSMartin K. Petersen 		       " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
15911da177e4SLinus Torvalds 	return 0;
15921da177e4SLinus Torvalds }
15931da177e4SLinus Torvalds 
1594c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256
15951da177e4SLinus Torvalds 
15961da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp,
15971da177e4SLinus Torvalds 			    struct sdebug_dev_info * devip)
15981da177e4SLinus Torvalds {
15991da177e4SLinus Torvalds 	unsigned int alloc_len;
1600c65b1445SDouglas Gilbert 	int lun_cnt, i, upper, num, n, wlun, lun;
16011da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
16021da177e4SLinus Torvalds 	int select_report = (int)cmd[2];
16031da177e4SLinus Torvalds 	struct scsi_lun *one_lun;
16041da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_RLUN_ARR_SZ];
1605c65b1445SDouglas Gilbert 	unsigned char * max_addr;
16061da177e4SLinus Torvalds 
16071da177e4SLinus Torvalds 	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
1608c65b1445SDouglas Gilbert 	if ((alloc_len < 4) || (select_report > 2)) {
16091da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
16101da177e4SLinus Torvalds 			       	0);
16111da177e4SLinus Torvalds 		return check_condition_result;
16121da177e4SLinus Torvalds 	}
16131da177e4SLinus Torvalds 	/* can produce response with up to 16k luns (lun 0 to lun 16383) */
16141da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
16151da177e4SLinus Torvalds 	lun_cnt = scsi_debug_max_luns;
1616c65b1445SDouglas Gilbert 	if (1 == select_report)
1617c65b1445SDouglas Gilbert 		lun_cnt = 0;
1618c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1619c65b1445SDouglas Gilbert 		--lun_cnt;
1620c65b1445SDouglas Gilbert 	wlun = (select_report > 0) ? 1 : 0;
1621c65b1445SDouglas Gilbert 	num = lun_cnt + wlun;
1622c65b1445SDouglas Gilbert 	arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1623c65b1445SDouglas Gilbert 	arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1624c65b1445SDouglas Gilbert 	n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1625c65b1445SDouglas Gilbert 			    sizeof(struct scsi_lun)), num);
1626c65b1445SDouglas Gilbert 	if (n < num) {
1627c65b1445SDouglas Gilbert 		wlun = 0;
1628c65b1445SDouglas Gilbert 		lun_cnt = n;
1629c65b1445SDouglas Gilbert 	}
16301da177e4SLinus Torvalds 	one_lun = (struct scsi_lun *) &arr[8];
1631c65b1445SDouglas Gilbert 	max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1632c65b1445SDouglas Gilbert 	for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1633c65b1445SDouglas Gilbert              ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1634c65b1445SDouglas Gilbert 	     i++, lun++) {
1635c65b1445SDouglas Gilbert 		upper = (lun >> 8) & 0x3f;
16361da177e4SLinus Torvalds 		if (upper)
16371da177e4SLinus Torvalds 			one_lun[i].scsi_lun[0] =
16381da177e4SLinus Torvalds 			    (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
1639c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = lun & 0xff;
16401da177e4SLinus Torvalds 	}
1641c65b1445SDouglas Gilbert 	if (wlun) {
1642c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1643c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1644c65b1445SDouglas Gilbert 		i++;
1645c65b1445SDouglas Gilbert 	}
1646c65b1445SDouglas Gilbert 	alloc_len = (unsigned char *)(one_lun + i) - arr;
16471da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr,
16481da177e4SLinus Torvalds 				    min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
16491da177e4SLinus Torvalds }
16501da177e4SLinus Torvalds 
1651c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
1652c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
1653c639d14eSFUJITA Tomonori {
1654c639d14eSFUJITA Tomonori 	int i, j, ret = -1;
1655c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
1656c639d14eSFUJITA Tomonori 	unsigned int offset;
1657c639d14eSFUJITA Tomonori 	struct scatterlist *sg;
1658c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
1659c639d14eSFUJITA Tomonori 
1660c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
1661c639d14eSFUJITA Tomonori 	buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
1662c639d14eSFUJITA Tomonori 	if (!buf)
1663c639d14eSFUJITA Tomonori 		return ret;
1664c639d14eSFUJITA Tomonori 
166521a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
1666c639d14eSFUJITA Tomonori 
1667c639d14eSFUJITA Tomonori 	offset = 0;
1668c639d14eSFUJITA Tomonori 	for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
1669c639d14eSFUJITA Tomonori 		kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1670c639d14eSFUJITA Tomonori 		if (!kaddr)
1671c639d14eSFUJITA Tomonori 			goto out;
1672c639d14eSFUJITA Tomonori 
1673c639d14eSFUJITA Tomonori 		for (j = 0; j < sg->length; j++)
1674c639d14eSFUJITA Tomonori 			*(kaddr + sg->offset + j) ^= *(buf + offset + j);
1675c639d14eSFUJITA Tomonori 
1676c639d14eSFUJITA Tomonori 		offset += sg->length;
1677c639d14eSFUJITA Tomonori 		kunmap_atomic(kaddr, KM_USER0);
1678c639d14eSFUJITA Tomonori 	}
1679c639d14eSFUJITA Tomonori 	ret = 0;
1680c639d14eSFUJITA Tomonori out:
1681c639d14eSFUJITA Tomonori 	kfree(buf);
1682c639d14eSFUJITA Tomonori 
1683c639d14eSFUJITA Tomonori 	return ret;
1684c639d14eSFUJITA Tomonori }
1685c639d14eSFUJITA Tomonori 
16861da177e4SLinus Torvalds /* When timer goes off this function is called. */
16871da177e4SLinus Torvalds static void timer_intr_handler(unsigned long indx)
16881da177e4SLinus Torvalds {
16891da177e4SLinus Torvalds 	struct sdebug_queued_cmd * sqcp;
16901da177e4SLinus Torvalds 	unsigned long iflags;
16911da177e4SLinus Torvalds 
16921da177e4SLinus Torvalds 	if (indx >= SCSI_DEBUG_CANQUEUE) {
16931da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
16941da177e4SLinus Torvalds 		       "large\n");
16951da177e4SLinus Torvalds 		return;
16961da177e4SLinus Torvalds 	}
16971da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
16981da177e4SLinus Torvalds 	sqcp = &queued_arr[(int)indx];
16991da177e4SLinus Torvalds 	if (! sqcp->in_use) {
17001da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
17011da177e4SLinus Torvalds 		       "interrupt\n");
17021da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
17031da177e4SLinus Torvalds 		return;
17041da177e4SLinus Torvalds 	}
17051da177e4SLinus Torvalds 	sqcp->in_use = 0;
17061da177e4SLinus Torvalds 	if (sqcp->done_funct) {
17071da177e4SLinus Torvalds 		sqcp->a_cmnd->result = sqcp->scsi_result;
17081da177e4SLinus Torvalds 		sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
17091da177e4SLinus Torvalds 	}
17101da177e4SLinus Torvalds 	sqcp->done_funct = NULL;
17111da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
17121da177e4SLinus Torvalds }
17131da177e4SLinus Torvalds 
17141da177e4SLinus Torvalds 
17158dea0d02SFUJITA Tomonori static struct sdebug_dev_info *
17168dea0d02SFUJITA Tomonori sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
17175cb2fc06SFUJITA Tomonori {
17185cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
17195cb2fc06SFUJITA Tomonori 
17205cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
17215cb2fc06SFUJITA Tomonori 	if (devip) {
17225cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
17235cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
17245cb2fc06SFUJITA Tomonori 	}
17255cb2fc06SFUJITA Tomonori 	return devip;
17265cb2fc06SFUJITA Tomonori }
17275cb2fc06SFUJITA Tomonori 
17281da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
17291da177e4SLinus Torvalds {
17301da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
17311da177e4SLinus Torvalds 	struct sdebug_dev_info * open_devip = NULL;
17321da177e4SLinus Torvalds 	struct sdebug_dev_info * devip =
17331da177e4SLinus Torvalds 			(struct sdebug_dev_info *)sdev->hostdata;
17341da177e4SLinus Torvalds 
17351da177e4SLinus Torvalds 	if (devip)
17361da177e4SLinus Torvalds 		return devip;
1737d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
17381da177e4SLinus Torvalds 	if (!sdbg_host) {
17391da177e4SLinus Torvalds                 printk(KERN_ERR "Host info NULL\n");
17401da177e4SLinus Torvalds 		return NULL;
17411da177e4SLinus Torvalds         }
17421da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
17431da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
17441da177e4SLinus Torvalds                     (devip->target == sdev->id) &&
17451da177e4SLinus Torvalds                     (devip->lun == sdev->lun))
17461da177e4SLinus Torvalds                         return devip;
17471da177e4SLinus Torvalds 		else {
17481da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
17491da177e4SLinus Torvalds 				open_devip = devip;
17501da177e4SLinus Torvalds 		}
17511da177e4SLinus Torvalds 	}
17525cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
17535cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
17545cb2fc06SFUJITA Tomonori 		if (!open_devip) {
17551da177e4SLinus Torvalds 			printk(KERN_ERR "%s: out of memory at line %d\n",
17561da177e4SLinus Torvalds 				__FUNCTION__, __LINE__);
17571da177e4SLinus Torvalds 			return NULL;
17581da177e4SLinus Torvalds 		}
17591da177e4SLinus Torvalds 	}
1760a75869d1SFUJITA Tomonori 
17611da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
17621da177e4SLinus Torvalds 	open_devip->target = sdev->id;
17631da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
17641da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
17651da177e4SLinus Torvalds 	open_devip->reset = 1;
17661da177e4SLinus Torvalds 	open_devip->used = 1;
17671da177e4SLinus Torvalds 	memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
17681da177e4SLinus Torvalds 	if (scsi_debug_dsense)
17691da177e4SLinus Torvalds 		open_devip->sense_buff[0] = 0x72;
17701da177e4SLinus Torvalds 	else {
17711da177e4SLinus Torvalds 		open_devip->sense_buff[0] = 0x70;
17721da177e4SLinus Torvalds 		open_devip->sense_buff[7] = 0xa;
17731da177e4SLinus Torvalds 	}
1774c65b1445SDouglas Gilbert 	if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
1775c65b1445SDouglas Gilbert 		open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
1776a75869d1SFUJITA Tomonori 
17771da177e4SLinus Torvalds 	return open_devip;
17781da177e4SLinus Torvalds }
17791da177e4SLinus Torvalds 
17808dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
17811da177e4SLinus Torvalds {
17828dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
17838dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
17848dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
178575ad23bcSNick Piggin 	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
17868dea0d02SFUJITA Tomonori 	return 0;
17878dea0d02SFUJITA Tomonori }
17881da177e4SLinus Torvalds 
17898dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
17908dea0d02SFUJITA Tomonori {
17918dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip;
1792a34c4e98SFUJITA Tomonori 
17931da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
17948dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
17958dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
17968dea0d02SFUJITA Tomonori 	if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
17978dea0d02SFUJITA Tomonori 		sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
17988dea0d02SFUJITA Tomonori 	devip = devInfoReg(sdp);
17998dea0d02SFUJITA Tomonori 	if (NULL == devip)
18008dea0d02SFUJITA Tomonori 		return 1;	/* no resources, will be marked offline */
18018dea0d02SFUJITA Tomonori 	sdp->hostdata = devip;
18028dea0d02SFUJITA Tomonori 	if (sdp->host->cmd_per_lun)
18038dea0d02SFUJITA Tomonori 		scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
18048dea0d02SFUJITA Tomonori 					sdp->host->cmd_per_lun);
18058dea0d02SFUJITA Tomonori 	blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
18068dea0d02SFUJITA Tomonori 	return 0;
18078dea0d02SFUJITA Tomonori }
18088dea0d02SFUJITA Tomonori 
18098dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
18108dea0d02SFUJITA Tomonori {
18118dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
18128dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
18138dea0d02SFUJITA Tomonori 
18148dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
18158dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
18168dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
18178dea0d02SFUJITA Tomonori 	if (devip) {
18188dea0d02SFUJITA Tomonori 		/* make this slot avaliable for re-use */
18198dea0d02SFUJITA Tomonori 		devip->used = 0;
18208dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
18218dea0d02SFUJITA Tomonori 	}
18228dea0d02SFUJITA Tomonori }
18238dea0d02SFUJITA Tomonori 
18248dea0d02SFUJITA Tomonori /* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
18258dea0d02SFUJITA Tomonori static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
18268dea0d02SFUJITA Tomonori {
18278dea0d02SFUJITA Tomonori 	unsigned long iflags;
18288dea0d02SFUJITA Tomonori 	int k;
18298dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
18308dea0d02SFUJITA Tomonori 
18318dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
18328dea0d02SFUJITA Tomonori 	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
18338dea0d02SFUJITA Tomonori 		sqcp = &queued_arr[k];
18348dea0d02SFUJITA Tomonori 		if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
18358dea0d02SFUJITA Tomonori 			del_timer_sync(&sqcp->cmnd_timer);
18368dea0d02SFUJITA Tomonori 			sqcp->in_use = 0;
18378dea0d02SFUJITA Tomonori 			sqcp->a_cmnd = NULL;
18388dea0d02SFUJITA Tomonori 			break;
18398dea0d02SFUJITA Tomonori 		}
18408dea0d02SFUJITA Tomonori 	}
18418dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
18428dea0d02SFUJITA Tomonori 	return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
18438dea0d02SFUJITA Tomonori }
18448dea0d02SFUJITA Tomonori 
18458dea0d02SFUJITA Tomonori /* Deletes (stops) timers of all queued commands */
18468dea0d02SFUJITA Tomonori static void stop_all_queued(void)
18478dea0d02SFUJITA Tomonori {
18488dea0d02SFUJITA Tomonori 	unsigned long iflags;
18498dea0d02SFUJITA Tomonori 	int k;
18508dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
18518dea0d02SFUJITA Tomonori 
18528dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
18538dea0d02SFUJITA Tomonori 	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
18548dea0d02SFUJITA Tomonori 		sqcp = &queued_arr[k];
18558dea0d02SFUJITA Tomonori 		if (sqcp->in_use && sqcp->a_cmnd) {
18568dea0d02SFUJITA Tomonori 			del_timer_sync(&sqcp->cmnd_timer);
18578dea0d02SFUJITA Tomonori 			sqcp->in_use = 0;
18588dea0d02SFUJITA Tomonori 			sqcp->a_cmnd = NULL;
18598dea0d02SFUJITA Tomonori 		}
18608dea0d02SFUJITA Tomonori 	}
18618dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
18621da177e4SLinus Torvalds }
18631da177e4SLinus Torvalds 
18641da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
18651da177e4SLinus Torvalds {
18661da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
18671da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: abort\n");
18681da177e4SLinus Torvalds 	++num_aborts;
18691da177e4SLinus Torvalds 	stop_queued_cmnd(SCpnt);
18701da177e4SLinus Torvalds 	return SUCCESS;
18711da177e4SLinus Torvalds }
18721da177e4SLinus Torvalds 
18731da177e4SLinus Torvalds static int scsi_debug_biosparam(struct scsi_device *sdev,
18741da177e4SLinus Torvalds 		struct block_device * bdev, sector_t capacity, int *info)
18751da177e4SLinus Torvalds {
18761da177e4SLinus Torvalds 	int res;
18771da177e4SLinus Torvalds 	unsigned char *buf;
18781da177e4SLinus Torvalds 
18791da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
18801da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: biosparam\n");
18811da177e4SLinus Torvalds 	buf = scsi_bios_ptable(bdev);
18821da177e4SLinus Torvalds 	if (buf) {
18831da177e4SLinus Torvalds 		res = scsi_partsize(buf, capacity,
18841da177e4SLinus Torvalds 				    &info[2], &info[0], &info[1]);
18851da177e4SLinus Torvalds 		kfree(buf);
18861da177e4SLinus Torvalds 		if (! res)
18871da177e4SLinus Torvalds 			return res;
18881da177e4SLinus Torvalds 	}
18891da177e4SLinus Torvalds 	info[0] = sdebug_heads;
18901da177e4SLinus Torvalds 	info[1] = sdebug_sectors_per;
18911da177e4SLinus Torvalds 	info[2] = sdebug_cylinders_per;
18921da177e4SLinus Torvalds 	return 0;
18931da177e4SLinus Torvalds }
18941da177e4SLinus Torvalds 
18951da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
18961da177e4SLinus Torvalds {
18971da177e4SLinus Torvalds 	struct sdebug_dev_info * devip;
18981da177e4SLinus Torvalds 
18991da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
19001da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: device_reset\n");
19011da177e4SLinus Torvalds 	++num_dev_resets;
19021da177e4SLinus Torvalds 	if (SCpnt) {
19031da177e4SLinus Torvalds 		devip = devInfoReg(SCpnt->device);
19041da177e4SLinus Torvalds 		if (devip)
19051da177e4SLinus Torvalds 			devip->reset = 1;
19061da177e4SLinus Torvalds 	}
19071da177e4SLinus Torvalds 	return SUCCESS;
19081da177e4SLinus Torvalds }
19091da177e4SLinus Torvalds 
19101da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
19111da177e4SLinus Torvalds {
19121da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
19131da177e4SLinus Torvalds         struct sdebug_dev_info * dev_info;
19141da177e4SLinus Torvalds         struct scsi_device * sdp;
19151da177e4SLinus Torvalds         struct Scsi_Host * hp;
19161da177e4SLinus Torvalds 
19171da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
19181da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: bus_reset\n");
19191da177e4SLinus Torvalds 	++num_bus_resets;
19201da177e4SLinus Torvalds 	if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
1921d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
19221da177e4SLinus Torvalds 		if (sdbg_host) {
19231da177e4SLinus Torvalds 			list_for_each_entry(dev_info,
19241da177e4SLinus Torvalds                                             &sdbg_host->dev_info_list,
19251da177e4SLinus Torvalds                                             dev_list)
19261da177e4SLinus Torvalds 				dev_info->reset = 1;
19271da177e4SLinus Torvalds 		}
19281da177e4SLinus Torvalds 	}
19291da177e4SLinus Torvalds 	return SUCCESS;
19301da177e4SLinus Torvalds }
19311da177e4SLinus Torvalds 
19321da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
19331da177e4SLinus Torvalds {
19341da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
19351da177e4SLinus Torvalds         struct sdebug_dev_info * dev_info;
19361da177e4SLinus Torvalds 
19371da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
19381da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: host_reset\n");
19391da177e4SLinus Torvalds 	++num_host_resets;
19401da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
19411da177e4SLinus Torvalds         list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
19421da177e4SLinus Torvalds                 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
19431da177e4SLinus Torvalds                                     dev_list)
19441da177e4SLinus Torvalds                         dev_info->reset = 1;
19451da177e4SLinus Torvalds         }
19461da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
19471da177e4SLinus Torvalds 	stop_all_queued();
19481da177e4SLinus Torvalds 	return SUCCESS;
19491da177e4SLinus Torvalds }
19501da177e4SLinus Torvalds 
19511da177e4SLinus Torvalds /* Initializes timers in queued array */
19521da177e4SLinus Torvalds static void __init init_all_queued(void)
19531da177e4SLinus Torvalds {
19541da177e4SLinus Torvalds 	unsigned long iflags;
19551da177e4SLinus Torvalds 	int k;
19561da177e4SLinus Torvalds 	struct sdebug_queued_cmd * sqcp;
19571da177e4SLinus Torvalds 
19581da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
19591da177e4SLinus Torvalds 	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
19601da177e4SLinus Torvalds 		sqcp = &queued_arr[k];
19611da177e4SLinus Torvalds 		init_timer(&sqcp->cmnd_timer);
19621da177e4SLinus Torvalds 		sqcp->in_use = 0;
19631da177e4SLinus Torvalds 		sqcp->a_cmnd = NULL;
19641da177e4SLinus Torvalds 	}
19651da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
19661da177e4SLinus Torvalds }
19671da177e4SLinus Torvalds 
1968f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
19695f2578e5SFUJITA Tomonori 				      unsigned long store_size)
19701da177e4SLinus Torvalds {
19711da177e4SLinus Torvalds 	struct partition * pp;
19721da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
19731da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
19741da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
19751da177e4SLinus Torvalds 
19761da177e4SLinus Torvalds 	/* assume partition table already zeroed */
1977f58b0efbSFUJITA Tomonori 	if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
19781da177e4SLinus Torvalds 		return;
19791da177e4SLinus Torvalds 	if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
19801da177e4SLinus Torvalds 		scsi_debug_num_parts = SDEBUG_MAX_PARTS;
19811da177e4SLinus Torvalds 		printk(KERN_WARNING "scsi_debug:build_parts: reducing "
19821da177e4SLinus Torvalds 				    "partitions to %d\n", SDEBUG_MAX_PARTS);
19831da177e4SLinus Torvalds 	}
1984c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
19851da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
19861da177e4SLinus Torvalds 			   / scsi_debug_num_parts;
19871da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
19881da177e4SLinus Torvalds         starts[0] = sdebug_sectors_per;
19891da177e4SLinus Torvalds 	for (k = 1; k < scsi_debug_num_parts; ++k)
19901da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
19911da177e4SLinus Torvalds 			    * heads_by_sects;
19921da177e4SLinus Torvalds 	starts[scsi_debug_num_parts] = num_sectors;
19931da177e4SLinus Torvalds 	starts[scsi_debug_num_parts + 1] = 0;
19941da177e4SLinus Torvalds 
19951da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
19961da177e4SLinus Torvalds 	ramp[511] = 0xAA;
19971da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
19981da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
19991da177e4SLinus Torvalds 		start_sec = starts[k];
20001da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
20011da177e4SLinus Torvalds 		pp->boot_ind = 0;
20021da177e4SLinus Torvalds 
20031da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
20041da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
20051da177e4SLinus Torvalds 			   / sdebug_sectors_per;
20061da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
20071da177e4SLinus Torvalds 
20081da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
20091da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
20101da177e4SLinus Torvalds 			       / sdebug_sectors_per;
20111da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
20121da177e4SLinus Torvalds 
20131da177e4SLinus Torvalds 		pp->start_sect = start_sec;
20141da177e4SLinus Torvalds 		pp->nr_sects = end_sec - start_sec + 1;
20151da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
20161da177e4SLinus Torvalds 	}
20171da177e4SLinus Torvalds }
20181da177e4SLinus Torvalds 
20191da177e4SLinus Torvalds static int schedule_resp(struct scsi_cmnd * cmnd,
20201da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip,
20211da177e4SLinus Torvalds 			 done_funct_t done, int scsi_result, int delta_jiff)
20221da177e4SLinus Torvalds {
20231da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
20241da177e4SLinus Torvalds 		if (scsi_result) {
20251da177e4SLinus Torvalds 			struct scsi_device * sdp = cmnd->device;
20261da177e4SLinus Torvalds 
2027c65b1445SDouglas Gilbert 			printk(KERN_INFO "scsi_debug:    <%u %u %u %u> "
2028c65b1445SDouglas Gilbert 			       "non-zero result=0x%x\n", sdp->host->host_no,
2029c65b1445SDouglas Gilbert 			       sdp->channel, sdp->id, sdp->lun, scsi_result);
20301da177e4SLinus Torvalds 		}
20311da177e4SLinus Torvalds 	}
20321da177e4SLinus Torvalds 	if (cmnd && devip) {
20331da177e4SLinus Torvalds 		/* simulate autosense by this driver */
20341da177e4SLinus Torvalds 		if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
20351da177e4SLinus Torvalds 			memcpy(cmnd->sense_buffer, devip->sense_buff,
20361da177e4SLinus Torvalds 			       (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
20371da177e4SLinus Torvalds 			       SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
20381da177e4SLinus Torvalds 	}
20391da177e4SLinus Torvalds 	if (delta_jiff <= 0) {
20401da177e4SLinus Torvalds 		if (cmnd)
20411da177e4SLinus Torvalds 			cmnd->result = scsi_result;
20421da177e4SLinus Torvalds 		if (done)
20431da177e4SLinus Torvalds 			done(cmnd);
20441da177e4SLinus Torvalds 		return 0;
20451da177e4SLinus Torvalds 	} else {
20461da177e4SLinus Torvalds 		unsigned long iflags;
20471da177e4SLinus Torvalds 		int k;
20481da177e4SLinus Torvalds 		struct sdebug_queued_cmd * sqcp = NULL;
20491da177e4SLinus Torvalds 
20501da177e4SLinus Torvalds 		spin_lock_irqsave(&queued_arr_lock, iflags);
20511da177e4SLinus Torvalds 		for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
20521da177e4SLinus Torvalds 			sqcp = &queued_arr[k];
20531da177e4SLinus Torvalds 			if (! sqcp->in_use)
20541da177e4SLinus Torvalds 				break;
20551da177e4SLinus Torvalds 		}
20561da177e4SLinus Torvalds 		if (k >= SCSI_DEBUG_CANQUEUE) {
20571da177e4SLinus Torvalds 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
20581da177e4SLinus Torvalds 			printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
20591da177e4SLinus Torvalds 			return 1;	/* report busy to mid level */
20601da177e4SLinus Torvalds 		}
20611da177e4SLinus Torvalds 		sqcp->in_use = 1;
20621da177e4SLinus Torvalds 		sqcp->a_cmnd = cmnd;
20631da177e4SLinus Torvalds 		sqcp->scsi_result = scsi_result;
20641da177e4SLinus Torvalds 		sqcp->done_funct = done;
20651da177e4SLinus Torvalds 		sqcp->cmnd_timer.function = timer_intr_handler;
20661da177e4SLinus Torvalds 		sqcp->cmnd_timer.data = k;
20671da177e4SLinus Torvalds 		sqcp->cmnd_timer.expires = jiffies + delta_jiff;
20681da177e4SLinus Torvalds 		add_timer(&sqcp->cmnd_timer);
20691da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
20701da177e4SLinus Torvalds 		if (cmnd)
20711da177e4SLinus Torvalds 			cmnd->result = 0;
20721da177e4SLinus Torvalds 		return 0;
20731da177e4SLinus Torvalds 	}
20741da177e4SLinus Torvalds }
207523183910SDouglas Gilbert /* Note: The following macros create attribute files in the
207623183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
207723183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
207823183910SDouglas Gilbert    as it can when the corresponding attribute in the
207923183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
208023183910SDouglas Gilbert  */
2081c65b1445SDouglas Gilbert module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2082c65b1445SDouglas Gilbert module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2083c65b1445SDouglas Gilbert module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2084c65b1445SDouglas Gilbert module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2085c65b1445SDouglas Gilbert module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
208623183910SDouglas Gilbert module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
2087c65b1445SDouglas Gilbert module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2088c65b1445SDouglas Gilbert module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2089c65b1445SDouglas Gilbert module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2090c65b1445SDouglas Gilbert module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2091c65b1445SDouglas Gilbert module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2092c65b1445SDouglas Gilbert module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2093c65b1445SDouglas Gilbert module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2094c65b1445SDouglas Gilbert module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
209523183910SDouglas Gilbert module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
209623183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
2097597136abSMartin K. Petersen module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
20981da177e4SLinus Torvalds 
20991da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
21001da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
21011da177e4SLinus Torvalds MODULE_LICENSE("GPL");
21021da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION);
21031da177e4SLinus Torvalds 
21041da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
21051da177e4SLinus Torvalds MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
2106c65b1445SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2107c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
2108beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
210923183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
2110c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2111c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
21121da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
2113c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
21146f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
21151da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
21161da177e4SLinus Torvalds MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
2117c65b1445SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
211823183910SDouglas Gilbert MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
2119597136abSMartin K. Petersen MODULE_PARM_DESC(sector_size, "hardware sector size in bytes (def=512)");
21201da177e4SLinus Torvalds 
21211da177e4SLinus Torvalds 
21221da177e4SLinus Torvalds static char sdebug_info[256];
21231da177e4SLinus Torvalds 
21241da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp)
21251da177e4SLinus Torvalds {
21261da177e4SLinus Torvalds 	sprintf(sdebug_info, "scsi_debug, version %s [%s], "
21271da177e4SLinus Torvalds 		"dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
21281da177e4SLinus Torvalds 		scsi_debug_version_date, scsi_debug_dev_size_mb,
21291da177e4SLinus Torvalds 		scsi_debug_opts);
21301da177e4SLinus Torvalds 	return sdebug_info;
21311da177e4SLinus Torvalds }
21321da177e4SLinus Torvalds 
21331da177e4SLinus Torvalds /* scsi_debug_proc_info
21341da177e4SLinus Torvalds  * Used if the driver currently has no own support for /proc/scsi
21351da177e4SLinus Torvalds  */
21361da177e4SLinus Torvalds static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
21371da177e4SLinus Torvalds 				int length, int inout)
21381da177e4SLinus Torvalds {
21391da177e4SLinus Torvalds 	int len, pos, begin;
21401da177e4SLinus Torvalds 	int orig_length;
21411da177e4SLinus Torvalds 
21421da177e4SLinus Torvalds 	orig_length = length;
21431da177e4SLinus Torvalds 
21441da177e4SLinus Torvalds 	if (inout == 1) {
21451da177e4SLinus Torvalds 		char arr[16];
21461da177e4SLinus Torvalds 		int minLen = length > 15 ? 15 : length;
21471da177e4SLinus Torvalds 
21481da177e4SLinus Torvalds 		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
21491da177e4SLinus Torvalds 			return -EACCES;
21501da177e4SLinus Torvalds 		memcpy(arr, buffer, minLen);
21511da177e4SLinus Torvalds 		arr[minLen] = '\0';
21521da177e4SLinus Torvalds 		if (1 != sscanf(arr, "%d", &pos))
21531da177e4SLinus Torvalds 			return -EINVAL;
21541da177e4SLinus Torvalds 		scsi_debug_opts = pos;
21551da177e4SLinus Torvalds 		if (scsi_debug_every_nth != 0)
21561da177e4SLinus Torvalds                         scsi_debug_cmnd_count = 0;
21571da177e4SLinus Torvalds 		return length;
21581da177e4SLinus Torvalds 	}
21591da177e4SLinus Torvalds 	begin = 0;
21601da177e4SLinus Torvalds 	pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
21611da177e4SLinus Torvalds 	    "%s [%s]\n"
21621da177e4SLinus Torvalds 	    "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
21631da177e4SLinus Torvalds 	    "every_nth=%d(curr:%d)\n"
21641da177e4SLinus Torvalds 	    "delay=%d, max_luns=%d, scsi_level=%d\n"
21651da177e4SLinus Torvalds 	    "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
21661da177e4SLinus Torvalds 	    "number of aborts=%d, device_reset=%d, bus_resets=%d, "
21671da177e4SLinus Torvalds 	    "host_resets=%d\n",
21681da177e4SLinus Torvalds 	    SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
21691da177e4SLinus Torvalds 	    scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
21701da177e4SLinus Torvalds 	    scsi_debug_cmnd_count, scsi_debug_delay,
21711da177e4SLinus Torvalds 	    scsi_debug_max_luns, scsi_debug_scsi_level,
2172597136abSMartin K. Petersen 	    scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
2173597136abSMartin K. Petersen 	    sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
2174597136abSMartin K. Petersen 	    num_host_resets);
21751da177e4SLinus Torvalds 	if (pos < offset) {
21761da177e4SLinus Torvalds 		len = 0;
21771da177e4SLinus Torvalds 		begin = pos;
21781da177e4SLinus Torvalds 	}
21791da177e4SLinus Torvalds 	*start = buffer + (offset - begin);	/* Start of wanted data */
21801da177e4SLinus Torvalds 	len -= (offset - begin);
21811da177e4SLinus Torvalds 	if (len > length)
21821da177e4SLinus Torvalds 		len = length;
21831da177e4SLinus Torvalds 	return len;
21841da177e4SLinus Torvalds }
21851da177e4SLinus Torvalds 
21861da177e4SLinus Torvalds static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
21871da177e4SLinus Torvalds {
21881da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
21891da177e4SLinus Torvalds }
21901da177e4SLinus Torvalds 
21911da177e4SLinus Torvalds static ssize_t sdebug_delay_store(struct device_driver * ddp,
21921da177e4SLinus Torvalds 				  const char * buf, size_t count)
21931da177e4SLinus Torvalds {
21941da177e4SLinus Torvalds         int delay;
21951da177e4SLinus Torvalds 	char work[20];
21961da177e4SLinus Torvalds 
21971da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
21981da177e4SLinus Torvalds 		if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
21991da177e4SLinus Torvalds 			scsi_debug_delay = delay;
22001da177e4SLinus Torvalds 			return count;
22011da177e4SLinus Torvalds 		}
22021da177e4SLinus Torvalds 	}
22031da177e4SLinus Torvalds 	return -EINVAL;
22041da177e4SLinus Torvalds }
22051da177e4SLinus Torvalds DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
22061da177e4SLinus Torvalds 	    sdebug_delay_store);
22071da177e4SLinus Torvalds 
22081da177e4SLinus Torvalds static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
22091da177e4SLinus Torvalds {
22101da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
22111da177e4SLinus Torvalds }
22121da177e4SLinus Torvalds 
22131da177e4SLinus Torvalds static ssize_t sdebug_opts_store(struct device_driver * ddp,
22141da177e4SLinus Torvalds 				 const char * buf, size_t count)
22151da177e4SLinus Torvalds {
22161da177e4SLinus Torvalds         int opts;
22171da177e4SLinus Torvalds 	char work[20];
22181da177e4SLinus Torvalds 
22191da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
22201da177e4SLinus Torvalds 		if (0 == strnicmp(work,"0x", 2)) {
22211da177e4SLinus Torvalds 			if (1 == sscanf(&work[2], "%x", &opts))
22221da177e4SLinus Torvalds 				goto opts_done;
22231da177e4SLinus Torvalds 		} else {
22241da177e4SLinus Torvalds 			if (1 == sscanf(work, "%d", &opts))
22251da177e4SLinus Torvalds 				goto opts_done;
22261da177e4SLinus Torvalds 		}
22271da177e4SLinus Torvalds 	}
22281da177e4SLinus Torvalds 	return -EINVAL;
22291da177e4SLinus Torvalds opts_done:
22301da177e4SLinus Torvalds 	scsi_debug_opts = opts;
22311da177e4SLinus Torvalds 	scsi_debug_cmnd_count = 0;
22321da177e4SLinus Torvalds 	return count;
22331da177e4SLinus Torvalds }
22341da177e4SLinus Torvalds DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
22351da177e4SLinus Torvalds 	    sdebug_opts_store);
22361da177e4SLinus Torvalds 
22371da177e4SLinus Torvalds static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
22381da177e4SLinus Torvalds {
22391da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
22401da177e4SLinus Torvalds }
22411da177e4SLinus Torvalds static ssize_t sdebug_ptype_store(struct device_driver * ddp,
22421da177e4SLinus Torvalds 				  const char * buf, size_t count)
22431da177e4SLinus Torvalds {
22441da177e4SLinus Torvalds         int n;
22451da177e4SLinus Torvalds 
22461da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
22471da177e4SLinus Torvalds 		scsi_debug_ptype = n;
22481da177e4SLinus Torvalds 		return count;
22491da177e4SLinus Torvalds 	}
22501da177e4SLinus Torvalds 	return -EINVAL;
22511da177e4SLinus Torvalds }
22521da177e4SLinus Torvalds DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
22531da177e4SLinus Torvalds 
22541da177e4SLinus Torvalds static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
22551da177e4SLinus Torvalds {
22561da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
22571da177e4SLinus Torvalds }
22581da177e4SLinus Torvalds static ssize_t sdebug_dsense_store(struct device_driver * ddp,
22591da177e4SLinus Torvalds 				  const char * buf, size_t count)
22601da177e4SLinus Torvalds {
22611da177e4SLinus Torvalds         int n;
22621da177e4SLinus Torvalds 
22631da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
22641da177e4SLinus Torvalds 		scsi_debug_dsense = n;
22651da177e4SLinus Torvalds 		return count;
22661da177e4SLinus Torvalds 	}
22671da177e4SLinus Torvalds 	return -EINVAL;
22681da177e4SLinus Torvalds }
22691da177e4SLinus Torvalds DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
22701da177e4SLinus Torvalds 	    sdebug_dsense_store);
22711da177e4SLinus Torvalds 
227223183910SDouglas Gilbert static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
227323183910SDouglas Gilbert {
227423183910SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
227523183910SDouglas Gilbert }
227623183910SDouglas Gilbert static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
227723183910SDouglas Gilbert 				    const char * buf, size_t count)
227823183910SDouglas Gilbert {
227923183910SDouglas Gilbert         int n;
228023183910SDouglas Gilbert 
228123183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
228223183910SDouglas Gilbert 		scsi_debug_fake_rw = n;
228323183910SDouglas Gilbert 		return count;
228423183910SDouglas Gilbert 	}
228523183910SDouglas Gilbert 	return -EINVAL;
228623183910SDouglas Gilbert }
228723183910SDouglas Gilbert DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
228823183910SDouglas Gilbert 	    sdebug_fake_rw_store);
228923183910SDouglas Gilbert 
2290c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2291c65b1445SDouglas Gilbert {
2292c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2293c65b1445SDouglas Gilbert }
2294c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2295c65b1445SDouglas Gilbert 				     const char * buf, size_t count)
2296c65b1445SDouglas Gilbert {
2297c65b1445SDouglas Gilbert         int n;
2298c65b1445SDouglas Gilbert 
2299c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2300c65b1445SDouglas Gilbert 		scsi_debug_no_lun_0 = n;
2301c65b1445SDouglas Gilbert 		return count;
2302c65b1445SDouglas Gilbert 	}
2303c65b1445SDouglas Gilbert 	return -EINVAL;
2304c65b1445SDouglas Gilbert }
2305c65b1445SDouglas Gilbert DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2306c65b1445SDouglas Gilbert 	    sdebug_no_lun_0_store);
2307c65b1445SDouglas Gilbert 
23081da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
23091da177e4SLinus Torvalds {
23101da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
23111da177e4SLinus Torvalds }
23121da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
23131da177e4SLinus Torvalds 				     const char * buf, size_t count)
23141da177e4SLinus Torvalds {
23151da177e4SLinus Torvalds         int n;
23161da177e4SLinus Torvalds 
23171da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
23181da177e4SLinus Torvalds 		scsi_debug_num_tgts = n;
23191da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
23201da177e4SLinus Torvalds 		return count;
23211da177e4SLinus Torvalds 	}
23221da177e4SLinus Torvalds 	return -EINVAL;
23231da177e4SLinus Torvalds }
23241da177e4SLinus Torvalds DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
23251da177e4SLinus Torvalds 	    sdebug_num_tgts_store);
23261da177e4SLinus Torvalds 
23271da177e4SLinus Torvalds static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
23281da177e4SLinus Torvalds {
23291da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
23301da177e4SLinus Torvalds }
23311da177e4SLinus Torvalds DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
23321da177e4SLinus Torvalds 
23331da177e4SLinus Torvalds static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
23341da177e4SLinus Torvalds {
23351da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
23361da177e4SLinus Torvalds }
23371da177e4SLinus Torvalds DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
23381da177e4SLinus Torvalds 
23391da177e4SLinus Torvalds static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
23401da177e4SLinus Torvalds {
23411da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
23421da177e4SLinus Torvalds }
23431da177e4SLinus Torvalds static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
23441da177e4SLinus Torvalds 				      const char * buf, size_t count)
23451da177e4SLinus Torvalds {
23461da177e4SLinus Torvalds         int nth;
23471da177e4SLinus Torvalds 
23481da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
23491da177e4SLinus Torvalds 		scsi_debug_every_nth = nth;
23501da177e4SLinus Torvalds 		scsi_debug_cmnd_count = 0;
23511da177e4SLinus Torvalds 		return count;
23521da177e4SLinus Torvalds 	}
23531da177e4SLinus Torvalds 	return -EINVAL;
23541da177e4SLinus Torvalds }
23551da177e4SLinus Torvalds DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
23561da177e4SLinus Torvalds 	    sdebug_every_nth_store);
23571da177e4SLinus Torvalds 
23581da177e4SLinus Torvalds static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
23591da177e4SLinus Torvalds {
23601da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
23611da177e4SLinus Torvalds }
23621da177e4SLinus Torvalds static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
23631da177e4SLinus Torvalds 				     const char * buf, size_t count)
23641da177e4SLinus Torvalds {
23651da177e4SLinus Torvalds         int n;
23661da177e4SLinus Torvalds 
23671da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
23681da177e4SLinus Torvalds 		scsi_debug_max_luns = n;
23691da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
23701da177e4SLinus Torvalds 		return count;
23711da177e4SLinus Torvalds 	}
23721da177e4SLinus Torvalds 	return -EINVAL;
23731da177e4SLinus Torvalds }
23741da177e4SLinus Torvalds DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
23751da177e4SLinus Torvalds 	    sdebug_max_luns_store);
23761da177e4SLinus Torvalds 
23771da177e4SLinus Torvalds static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
23781da177e4SLinus Torvalds {
23791da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
23801da177e4SLinus Torvalds }
23811da177e4SLinus Torvalds DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
23821da177e4SLinus Torvalds 
2383c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2384c65b1445SDouglas Gilbert {
2385c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2386c65b1445SDouglas Gilbert }
2387c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2388c65b1445SDouglas Gilbert 				       const char * buf, size_t count)
2389c65b1445SDouglas Gilbert {
2390c65b1445SDouglas Gilbert         int n;
2391c65b1445SDouglas Gilbert 
2392c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2393c65b1445SDouglas Gilbert 		scsi_debug_virtual_gb = n;
239428898873SFUJITA Tomonori 
239528898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
239628898873SFUJITA Tomonori 
2397c65b1445SDouglas Gilbert 		return count;
2398c65b1445SDouglas Gilbert 	}
2399c65b1445SDouglas Gilbert 	return -EINVAL;
2400c65b1445SDouglas Gilbert }
2401c65b1445SDouglas Gilbert DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2402c65b1445SDouglas Gilbert 	    sdebug_virtual_gb_store);
2403c65b1445SDouglas Gilbert 
24041da177e4SLinus Torvalds static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
24051da177e4SLinus Torvalds {
24061da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
24071da177e4SLinus Torvalds }
24081da177e4SLinus Torvalds 
24091da177e4SLinus Torvalds static ssize_t sdebug_add_host_store(struct device_driver * ddp,
24101da177e4SLinus Torvalds 				     const char * buf, size_t count)
24111da177e4SLinus Torvalds {
24121da177e4SLinus Torvalds 	int delta_hosts;
24131da177e4SLinus Torvalds 
2414f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
24151da177e4SLinus Torvalds 		return -EINVAL;
24161da177e4SLinus Torvalds 	if (delta_hosts > 0) {
24171da177e4SLinus Torvalds 		do {
24181da177e4SLinus Torvalds 			sdebug_add_adapter();
24191da177e4SLinus Torvalds 		} while (--delta_hosts);
24201da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
24211da177e4SLinus Torvalds 		do {
24221da177e4SLinus Torvalds 			sdebug_remove_adapter();
24231da177e4SLinus Torvalds 		} while (++delta_hosts);
24241da177e4SLinus Torvalds 	}
24251da177e4SLinus Torvalds 	return count;
24261da177e4SLinus Torvalds }
24271da177e4SLinus Torvalds DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
24281da177e4SLinus Torvalds 	    sdebug_add_host_store);
24291da177e4SLinus Torvalds 
243023183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
243123183910SDouglas Gilbert 					  char * buf)
243223183910SDouglas Gilbert {
243323183910SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
243423183910SDouglas Gilbert }
243523183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
243623183910SDouglas Gilbert 					   const char * buf, size_t count)
243723183910SDouglas Gilbert {
243823183910SDouglas Gilbert 	int n;
243923183910SDouglas Gilbert 
244023183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
244123183910SDouglas Gilbert 		scsi_debug_vpd_use_hostno = n;
244223183910SDouglas Gilbert 		return count;
244323183910SDouglas Gilbert 	}
244423183910SDouglas Gilbert 	return -EINVAL;
244523183910SDouglas Gilbert }
244623183910SDouglas Gilbert DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
244723183910SDouglas Gilbert 	    sdebug_vpd_use_hostno_store);
244823183910SDouglas Gilbert 
2449597136abSMartin K. Petersen static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf)
2450597136abSMartin K. Petersen {
2451597136abSMartin K. Petersen 	return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
2452597136abSMartin K. Petersen }
2453597136abSMartin K. Petersen DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL);
2454597136abSMartin K. Petersen 
245523183910SDouglas Gilbert /* Note: The following function creates attribute files in the
245623183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
245723183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
245823183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
245923183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
246023183910SDouglas Gilbert  */
24616ecaff7fSRandy Dunlap static int do_create_driverfs_files(void)
24621da177e4SLinus Torvalds {
24636ecaff7fSRandy Dunlap 	int ret;
24646ecaff7fSRandy Dunlap 
24656ecaff7fSRandy Dunlap 	ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
24666ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
24676ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
24686ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
24696ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
247023183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
24716ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
247223183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
24736ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
247423183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
24756ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
24766ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
24776ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
247823183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
247923183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2480597136abSMartin K. Petersen 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
24816ecaff7fSRandy Dunlap 	return ret;
24821da177e4SLinus Torvalds }
24831da177e4SLinus Torvalds 
24841da177e4SLinus Torvalds static void do_remove_driverfs_files(void)
24851da177e4SLinus Torvalds {
2486597136abSMartin K. Petersen 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
248723183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
248823183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
24891da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
24901da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
24911da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
24921da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
249323183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
249423183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
24951da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
249623183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
24971da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
24981da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
24991da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
25001da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
25011da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
25021da177e4SLinus Torvalds }
25031da177e4SLinus Torvalds 
25048dea0d02SFUJITA Tomonori static void pseudo_0_release(struct device *dev)
25058dea0d02SFUJITA Tomonori {
25068dea0d02SFUJITA Tomonori 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
25078dea0d02SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
25088dea0d02SFUJITA Tomonori }
25098dea0d02SFUJITA Tomonori 
25108dea0d02SFUJITA Tomonori static struct device pseudo_primary = {
25118dea0d02SFUJITA Tomonori 	.bus_id		= "pseudo_0",
25128dea0d02SFUJITA Tomonori 	.release	= pseudo_0_release,
25138dea0d02SFUJITA Tomonori };
25148dea0d02SFUJITA Tomonori 
25151da177e4SLinus Torvalds static int __init scsi_debug_init(void)
25161da177e4SLinus Torvalds {
25175f2578e5SFUJITA Tomonori 	unsigned long sz;
25181da177e4SLinus Torvalds 	int host_to_add;
25191da177e4SLinus Torvalds 	int k;
25206ecaff7fSRandy Dunlap 	int ret;
25211da177e4SLinus Torvalds 
2522597136abSMartin K. Petersen 	switch (scsi_debug_sector_size) {
2523597136abSMartin K. Petersen 	case  512:
2524597136abSMartin K. Petersen 	case 1024:
2525597136abSMartin K. Petersen 	case 2048:
2526597136abSMartin K. Petersen 	case 4096:
2527597136abSMartin K. Petersen 		break;
2528597136abSMartin K. Petersen 	default:
2529597136abSMartin K. Petersen 		printk(KERN_ERR "scsi_debug_init: invalid sector_size %u\n",
2530597136abSMartin K. Petersen 		       scsi_debug_sector_size);
2531597136abSMartin K. Petersen 		return -EINVAL;
2532597136abSMartin K. Petersen 	}
2533597136abSMartin K. Petersen 
25341da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb < 1)
25351da177e4SLinus Torvalds 		scsi_debug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
25365f2578e5SFUJITA Tomonori 	sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
2537597136abSMartin K. Petersen 	sdebug_store_sectors = sz / scsi_debug_sector_size;
253828898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
25391da177e4SLinus Torvalds 
25401da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
25411da177e4SLinus Torvalds 	sdebug_heads = 8;
25421da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
25431da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb >= 16)
25441da177e4SLinus Torvalds 		sdebug_heads = 32;
25451da177e4SLinus Torvalds 	else if (scsi_debug_dev_size_mb >= 256)
25461da177e4SLinus Torvalds 		sdebug_heads = 64;
25471da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
25481da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
25491da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
25501da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
25511da177e4SLinus Torvalds 		sdebug_heads = 255;
25521da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
25531da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
25541da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
25551da177e4SLinus Torvalds 	}
25561da177e4SLinus Torvalds 
25571da177e4SLinus Torvalds 	fake_storep = vmalloc(sz);
25581da177e4SLinus Torvalds 	if (NULL == fake_storep) {
25591da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
25601da177e4SLinus Torvalds 		return -ENOMEM;
25611da177e4SLinus Torvalds 	}
25621da177e4SLinus Torvalds 	memset(fake_storep, 0, sz);
25631da177e4SLinus Torvalds 	if (scsi_debug_num_parts > 0)
2564f58b0efbSFUJITA Tomonori 		sdebug_build_parts(fake_storep, sz);
25651da177e4SLinus Torvalds 
25666ecaff7fSRandy Dunlap 	ret = device_register(&pseudo_primary);
25676ecaff7fSRandy Dunlap 	if (ret < 0) {
25686ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
25696ecaff7fSRandy Dunlap 			ret);
25706ecaff7fSRandy Dunlap 		goto free_vm;
25716ecaff7fSRandy Dunlap 	}
25726ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
25736ecaff7fSRandy Dunlap 	if (ret < 0) {
25746ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
25756ecaff7fSRandy Dunlap 			ret);
25766ecaff7fSRandy Dunlap 		goto dev_unreg;
25776ecaff7fSRandy Dunlap 	}
25786ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
25796ecaff7fSRandy Dunlap 	if (ret < 0) {
25806ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
25816ecaff7fSRandy Dunlap 			ret);
25826ecaff7fSRandy Dunlap 		goto bus_unreg;
25836ecaff7fSRandy Dunlap 	}
25846ecaff7fSRandy Dunlap 	ret = do_create_driverfs_files();
25856ecaff7fSRandy Dunlap 	if (ret < 0) {
25866ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
25876ecaff7fSRandy Dunlap 			ret);
25886ecaff7fSRandy Dunlap 		goto del_files;
25896ecaff7fSRandy Dunlap 	}
25901da177e4SLinus Torvalds 
25916ecaff7fSRandy Dunlap 	init_all_queued();
25921da177e4SLinus Torvalds 
25931da177e4SLinus Torvalds 	host_to_add = scsi_debug_add_host;
25941da177e4SLinus Torvalds         scsi_debug_add_host = 0;
25951da177e4SLinus Torvalds 
25961da177e4SLinus Torvalds         for (k = 0; k < host_to_add; k++) {
25971da177e4SLinus Torvalds                 if (sdebug_add_adapter()) {
25981da177e4SLinus Torvalds                         printk(KERN_ERR "scsi_debug_init: "
25991da177e4SLinus Torvalds                                "sdebug_add_adapter failed k=%d\n", k);
26001da177e4SLinus Torvalds                         break;
26011da177e4SLinus Torvalds                 }
26021da177e4SLinus Torvalds         }
26031da177e4SLinus Torvalds 
26041da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
26051da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
26061da177e4SLinus Torvalds 		       scsi_debug_add_host);
26071da177e4SLinus Torvalds 	}
26081da177e4SLinus Torvalds 	return 0;
26096ecaff7fSRandy Dunlap 
26106ecaff7fSRandy Dunlap del_files:
26116ecaff7fSRandy Dunlap 	do_remove_driverfs_files();
26126ecaff7fSRandy Dunlap 	driver_unregister(&sdebug_driverfs_driver);
26136ecaff7fSRandy Dunlap bus_unreg:
26146ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
26156ecaff7fSRandy Dunlap dev_unreg:
26166ecaff7fSRandy Dunlap 	device_unregister(&pseudo_primary);
26176ecaff7fSRandy Dunlap free_vm:
26186ecaff7fSRandy Dunlap 	vfree(fake_storep);
26196ecaff7fSRandy Dunlap 
26206ecaff7fSRandy Dunlap 	return ret;
26211da177e4SLinus Torvalds }
26221da177e4SLinus Torvalds 
26231da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
26241da177e4SLinus Torvalds {
26251da177e4SLinus Torvalds 	int k = scsi_debug_add_host;
26261da177e4SLinus Torvalds 
26271da177e4SLinus Torvalds 	stop_all_queued();
26281da177e4SLinus Torvalds 	for (; k; k--)
26291da177e4SLinus Torvalds 		sdebug_remove_adapter();
26301da177e4SLinus Torvalds 	do_remove_driverfs_files();
26311da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
26321da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
26331da177e4SLinus Torvalds 	device_unregister(&pseudo_primary);
26341da177e4SLinus Torvalds 
26351da177e4SLinus Torvalds 	vfree(fake_storep);
26361da177e4SLinus Torvalds }
26371da177e4SLinus Torvalds 
26381da177e4SLinus Torvalds device_initcall(scsi_debug_init);
26391da177e4SLinus Torvalds module_exit(scsi_debug_exit);
26401da177e4SLinus Torvalds 
26411da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev)
26421da177e4SLinus Torvalds {
26431da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
26441da177e4SLinus Torvalds 
26451da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
26461da177e4SLinus Torvalds         kfree(sdbg_host);
26471da177e4SLinus Torvalds }
26481da177e4SLinus Torvalds 
26491da177e4SLinus Torvalds static int sdebug_add_adapter(void)
26501da177e4SLinus Torvalds {
26511da177e4SLinus Torvalds 	int k, devs_per_host;
26521da177e4SLinus Torvalds         int error = 0;
26531da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
26548b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
26551da177e4SLinus Torvalds 
265624669f75SJes Sorensen         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
26571da177e4SLinus Torvalds         if (NULL == sdbg_host) {
26581da177e4SLinus Torvalds                 printk(KERN_ERR "%s: out of memory at line %d\n",
26591da177e4SLinus Torvalds                        __FUNCTION__, __LINE__);
26601da177e4SLinus Torvalds                 return -ENOMEM;
26611da177e4SLinus Torvalds         }
26621da177e4SLinus Torvalds 
26631da177e4SLinus Torvalds         INIT_LIST_HEAD(&sdbg_host->dev_info_list);
26641da177e4SLinus Torvalds 
26651da177e4SLinus Torvalds 	devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
26661da177e4SLinus Torvalds         for (k = 0; k < devs_per_host; k++) {
26675cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
26685cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
26691da177e4SLinus Torvalds                         printk(KERN_ERR "%s: out of memory at line %d\n",
26701da177e4SLinus Torvalds                                __FUNCTION__, __LINE__);
26711da177e4SLinus Torvalds                         error = -ENOMEM;
26721da177e4SLinus Torvalds 			goto clean;
26731da177e4SLinus Torvalds                 }
26741da177e4SLinus Torvalds         }
26751da177e4SLinus Torvalds 
26761da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
26771da177e4SLinus Torvalds         list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
26781da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
26791da177e4SLinus Torvalds 
26801da177e4SLinus Torvalds         sdbg_host->dev.bus = &pseudo_lld_bus;
26811da177e4SLinus Torvalds         sdbg_host->dev.parent = &pseudo_primary;
26821da177e4SLinus Torvalds         sdbg_host->dev.release = &sdebug_release_adapter;
26831da177e4SLinus Torvalds         sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
26841da177e4SLinus Torvalds 
26851da177e4SLinus Torvalds         error = device_register(&sdbg_host->dev);
26861da177e4SLinus Torvalds 
26871da177e4SLinus Torvalds         if (error)
26881da177e4SLinus Torvalds 		goto clean;
26891da177e4SLinus Torvalds 
26901da177e4SLinus Torvalds 	++scsi_debug_add_host;
26911da177e4SLinus Torvalds         return error;
26921da177e4SLinus Torvalds 
26931da177e4SLinus Torvalds clean:
26948b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
26958b40228fSFUJITA Tomonori 				 dev_list) {
26961da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
26971da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
26981da177e4SLinus Torvalds 	}
26991da177e4SLinus Torvalds 
27001da177e4SLinus Torvalds 	kfree(sdbg_host);
27011da177e4SLinus Torvalds         return error;
27021da177e4SLinus Torvalds }
27031da177e4SLinus Torvalds 
27041da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
27051da177e4SLinus Torvalds {
27061da177e4SLinus Torvalds         struct sdebug_host_info * sdbg_host = NULL;
27071da177e4SLinus Torvalds 
27081da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
27091da177e4SLinus Torvalds         if (!list_empty(&sdebug_host_list)) {
27101da177e4SLinus Torvalds                 sdbg_host = list_entry(sdebug_host_list.prev,
27111da177e4SLinus Torvalds                                        struct sdebug_host_info, host_list);
27121da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
27131da177e4SLinus Torvalds 	}
27141da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
27151da177e4SLinus Torvalds 
27161da177e4SLinus Torvalds 	if (!sdbg_host)
27171da177e4SLinus Torvalds 		return;
27181da177e4SLinus Torvalds 
27191da177e4SLinus Torvalds         device_unregister(&sdbg_host->dev);
27201da177e4SLinus Torvalds         --scsi_debug_add_host;
27211da177e4SLinus Torvalds }
27221da177e4SLinus Torvalds 
2723639db475SFUJITA Tomonori static
2724639db475SFUJITA Tomonori int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
2725639db475SFUJITA Tomonori {
2726639db475SFUJITA Tomonori 	unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
2727639db475SFUJITA Tomonori 	int len, k;
2728639db475SFUJITA Tomonori 	unsigned int num;
2729639db475SFUJITA Tomonori 	unsigned long long lba;
2730639db475SFUJITA Tomonori 	int errsts = 0;
2731639db475SFUJITA Tomonori 	int target = SCpnt->device->id;
2732639db475SFUJITA Tomonori 	struct sdebug_dev_info *devip = NULL;
2733639db475SFUJITA Tomonori 	int inj_recovered = 0;
2734639db475SFUJITA Tomonori 	int inj_transport = 0;
2735639db475SFUJITA Tomonori 	int delay_override = 0;
2736639db475SFUJITA Tomonori 
2737639db475SFUJITA Tomonori 	scsi_set_resid(SCpnt, 0);
2738639db475SFUJITA Tomonori 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
2739639db475SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: cmd ");
2740639db475SFUJITA Tomonori 		for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
2741639db475SFUJITA Tomonori 			printk("%02x ", (int)cmd[k]);
2742639db475SFUJITA Tomonori 		printk("\n");
2743639db475SFUJITA Tomonori 	}
2744639db475SFUJITA Tomonori 
2745639db475SFUJITA Tomonori 	if (target == SCpnt->device->host->hostt->this_id) {
2746639db475SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: initiator's id used as "
2747639db475SFUJITA Tomonori 		       "target!\n");
2748639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
2749639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
2750639db475SFUJITA Tomonori 	}
2751639db475SFUJITA Tomonori 
2752639db475SFUJITA Tomonori 	if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
2753639db475SFUJITA Tomonori 	    (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
2754639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
2755639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
2756639db475SFUJITA Tomonori 	devip = devInfoReg(SCpnt->device);
2757639db475SFUJITA Tomonori 	if (NULL == devip)
2758639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
2759639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
2760639db475SFUJITA Tomonori 
2761639db475SFUJITA Tomonori 	if ((scsi_debug_every_nth != 0) &&
2762639db475SFUJITA Tomonori 	    (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
2763639db475SFUJITA Tomonori 		scsi_debug_cmnd_count = 0;
2764639db475SFUJITA Tomonori 		if (scsi_debug_every_nth < -1)
2765639db475SFUJITA Tomonori 			scsi_debug_every_nth = -1;
2766639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
2767639db475SFUJITA Tomonori 			return 0; /* ignore command causing timeout */
2768639db475SFUJITA Tomonori 		else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
2769639db475SFUJITA Tomonori 			inj_recovered = 1; /* to reads and writes below */
2770639db475SFUJITA Tomonori 		else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
2771639db475SFUJITA Tomonori 			inj_transport = 1; /* to reads and writes below */
2772639db475SFUJITA Tomonori 	}
2773639db475SFUJITA Tomonori 
2774639db475SFUJITA Tomonori 	if (devip->wlun) {
2775639db475SFUJITA Tomonori 		switch (*cmd) {
2776639db475SFUJITA Tomonori 		case INQUIRY:
2777639db475SFUJITA Tomonori 		case REQUEST_SENSE:
2778639db475SFUJITA Tomonori 		case TEST_UNIT_READY:
2779639db475SFUJITA Tomonori 		case REPORT_LUNS:
2780639db475SFUJITA Tomonori 			break;  /* only allowable wlun commands */
2781639db475SFUJITA Tomonori 		default:
2782639db475SFUJITA Tomonori 			if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2783639db475SFUJITA Tomonori 				printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
2784639db475SFUJITA Tomonori 				       "not supported for wlun\n", *cmd);
2785639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
2786639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
2787639db475SFUJITA Tomonori 			errsts = check_condition_result;
2788639db475SFUJITA Tomonori 			return schedule_resp(SCpnt, devip, done, errsts,
2789639db475SFUJITA Tomonori 					     0);
2790639db475SFUJITA Tomonori 		}
2791639db475SFUJITA Tomonori 	}
2792639db475SFUJITA Tomonori 
2793639db475SFUJITA Tomonori 	switch (*cmd) {
2794639db475SFUJITA Tomonori 	case INQUIRY:     /* mandatory, ignore unit attention */
2795639db475SFUJITA Tomonori 		delay_override = 1;
2796639db475SFUJITA Tomonori 		errsts = resp_inquiry(SCpnt, target, devip);
2797639db475SFUJITA Tomonori 		break;
2798639db475SFUJITA Tomonori 	case REQUEST_SENSE:	/* mandatory, ignore unit attention */
2799639db475SFUJITA Tomonori 		delay_override = 1;
2800639db475SFUJITA Tomonori 		errsts = resp_requests(SCpnt, devip);
2801639db475SFUJITA Tomonori 		break;
2802639db475SFUJITA Tomonori 	case REZERO_UNIT:	/* actually this is REWIND for SSC */
2803639db475SFUJITA Tomonori 	case START_STOP:
2804639db475SFUJITA Tomonori 		errsts = resp_start_stop(SCpnt, devip);
2805639db475SFUJITA Tomonori 		break;
2806639db475SFUJITA Tomonori 	case ALLOW_MEDIUM_REMOVAL:
2807639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2808639db475SFUJITA Tomonori 		if (errsts)
2809639db475SFUJITA Tomonori 			break;
2810639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2811639db475SFUJITA Tomonori 			printk(KERN_INFO "scsi_debug: Medium removal %s\n",
2812639db475SFUJITA Tomonori 			       cmd[4] ? "inhibited" : "enabled");
2813639db475SFUJITA Tomonori 		break;
2814639db475SFUJITA Tomonori 	case SEND_DIAGNOSTIC:     /* mandatory */
2815639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2816639db475SFUJITA Tomonori 		break;
2817639db475SFUJITA Tomonori 	case TEST_UNIT_READY:     /* mandatory */
2818639db475SFUJITA Tomonori 		delay_override = 1;
2819639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
2820639db475SFUJITA Tomonori 		break;
2821639db475SFUJITA Tomonori 	case RESERVE:
2822639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2823639db475SFUJITA Tomonori 		break;
2824639db475SFUJITA Tomonori 	case RESERVE_10:
2825639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2826639db475SFUJITA Tomonori 		break;
2827639db475SFUJITA Tomonori 	case RELEASE:
2828639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2829639db475SFUJITA Tomonori 		break;
2830639db475SFUJITA Tomonori 	case RELEASE_10:
2831639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2832639db475SFUJITA Tomonori 		break;
2833639db475SFUJITA Tomonori 	case READ_CAPACITY:
2834639db475SFUJITA Tomonori 		errsts = resp_readcap(SCpnt, devip);
2835639db475SFUJITA Tomonori 		break;
2836639db475SFUJITA Tomonori 	case SERVICE_ACTION_IN:
2837639db475SFUJITA Tomonori 		if (SAI_READ_CAPACITY_16 != cmd[1]) {
2838639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
2839639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
2840639db475SFUJITA Tomonori 			errsts = check_condition_result;
2841639db475SFUJITA Tomonori 			break;
2842639db475SFUJITA Tomonori 		}
2843639db475SFUJITA Tomonori 		errsts = resp_readcap16(SCpnt, devip);
2844639db475SFUJITA Tomonori 		break;
2845639db475SFUJITA Tomonori 	case MAINTENANCE_IN:
2846639db475SFUJITA Tomonori 		if (MI_REPORT_TARGET_PGS != cmd[1]) {
2847639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
2848639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
2849639db475SFUJITA Tomonori 			errsts = check_condition_result;
2850639db475SFUJITA Tomonori 			break;
2851639db475SFUJITA Tomonori 		}
2852639db475SFUJITA Tomonori 		errsts = resp_report_tgtpgs(SCpnt, devip);
2853639db475SFUJITA Tomonori 		break;
2854639db475SFUJITA Tomonori 	case READ_16:
2855639db475SFUJITA Tomonori 	case READ_12:
2856639db475SFUJITA Tomonori 	case READ_10:
2857639db475SFUJITA Tomonori 	case READ_6:
2858639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
2859639db475SFUJITA Tomonori 		if (errsts)
2860639db475SFUJITA Tomonori 			break;
2861639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
2862639db475SFUJITA Tomonori 			break;
2863639db475SFUJITA Tomonori 		get_data_transfer_info(cmd, &lba, &num);
2864639db475SFUJITA Tomonori 		errsts = resp_read(SCpnt, lba, num, devip);
2865639db475SFUJITA Tomonori 		if (inj_recovered && (0 == errsts)) {
2866639db475SFUJITA Tomonori 			mk_sense_buffer(devip, RECOVERED_ERROR,
2867639db475SFUJITA Tomonori 					THRESHOLD_EXCEEDED, 0);
2868639db475SFUJITA Tomonori 			errsts = check_condition_result;
2869639db475SFUJITA Tomonori 		} else if (inj_transport && (0 == errsts)) {
2870639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ABORTED_COMMAND,
2871639db475SFUJITA Tomonori 					TRANSPORT_PROBLEM, ACK_NAK_TO);
2872639db475SFUJITA Tomonori 			errsts = check_condition_result;
2873639db475SFUJITA Tomonori 		}
2874639db475SFUJITA Tomonori 		break;
2875639db475SFUJITA Tomonori 	case REPORT_LUNS:	/* mandatory, ignore unit attention */
2876639db475SFUJITA Tomonori 		delay_override = 1;
2877639db475SFUJITA Tomonori 		errsts = resp_report_luns(SCpnt, devip);
2878639db475SFUJITA Tomonori 		break;
2879639db475SFUJITA Tomonori 	case VERIFY:		/* 10 byte SBC-2 command */
2880639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
2881639db475SFUJITA Tomonori 		break;
2882639db475SFUJITA Tomonori 	case WRITE_16:
2883639db475SFUJITA Tomonori 	case WRITE_12:
2884639db475SFUJITA Tomonori 	case WRITE_10:
2885639db475SFUJITA Tomonori 	case WRITE_6:
2886639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
2887639db475SFUJITA Tomonori 		if (errsts)
2888639db475SFUJITA Tomonori 			break;
2889639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
2890639db475SFUJITA Tomonori 			break;
2891639db475SFUJITA Tomonori 		get_data_transfer_info(cmd, &lba, &num);
2892639db475SFUJITA Tomonori 		errsts = resp_write(SCpnt, lba, num, devip);
2893639db475SFUJITA Tomonori 		if (inj_recovered && (0 == errsts)) {
2894639db475SFUJITA Tomonori 			mk_sense_buffer(devip, RECOVERED_ERROR,
2895639db475SFUJITA Tomonori 					THRESHOLD_EXCEEDED, 0);
2896639db475SFUJITA Tomonori 			errsts = check_condition_result;
2897639db475SFUJITA Tomonori 		}
2898639db475SFUJITA Tomonori 		break;
2899639db475SFUJITA Tomonori 	case MODE_SENSE:
2900639db475SFUJITA Tomonori 	case MODE_SENSE_10:
2901639db475SFUJITA Tomonori 		errsts = resp_mode_sense(SCpnt, target, devip);
2902639db475SFUJITA Tomonori 		break;
2903639db475SFUJITA Tomonori 	case MODE_SELECT:
2904639db475SFUJITA Tomonori 		errsts = resp_mode_select(SCpnt, 1, devip);
2905639db475SFUJITA Tomonori 		break;
2906639db475SFUJITA Tomonori 	case MODE_SELECT_10:
2907639db475SFUJITA Tomonori 		errsts = resp_mode_select(SCpnt, 0, devip);
2908639db475SFUJITA Tomonori 		break;
2909639db475SFUJITA Tomonori 	case LOG_SENSE:
2910639db475SFUJITA Tomonori 		errsts = resp_log_sense(SCpnt, devip);
2911639db475SFUJITA Tomonori 		break;
2912639db475SFUJITA Tomonori 	case SYNCHRONIZE_CACHE:
2913639db475SFUJITA Tomonori 		delay_override = 1;
2914639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
2915639db475SFUJITA Tomonori 		break;
2916639db475SFUJITA Tomonori 	case WRITE_BUFFER:
2917639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2918639db475SFUJITA Tomonori 		break;
2919639db475SFUJITA Tomonori 	case XDWRITEREAD_10:
2920639db475SFUJITA Tomonori 		if (!scsi_bidi_cmnd(SCpnt)) {
2921639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
2922639db475SFUJITA Tomonori 					INVALID_FIELD_IN_CDB, 0);
2923639db475SFUJITA Tomonori 			errsts = check_condition_result;
2924639db475SFUJITA Tomonori 			break;
2925639db475SFUJITA Tomonori 		}
2926639db475SFUJITA Tomonori 
2927639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
2928639db475SFUJITA Tomonori 		if (errsts)
2929639db475SFUJITA Tomonori 			break;
2930639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
2931639db475SFUJITA Tomonori 			break;
2932639db475SFUJITA Tomonori 		get_data_transfer_info(cmd, &lba, &num);
2933639db475SFUJITA Tomonori 		errsts = resp_read(SCpnt, lba, num, devip);
2934639db475SFUJITA Tomonori 		if (errsts)
2935639db475SFUJITA Tomonori 			break;
2936639db475SFUJITA Tomonori 		errsts = resp_write(SCpnt, lba, num, devip);
2937639db475SFUJITA Tomonori 		if (errsts)
2938639db475SFUJITA Tomonori 			break;
2939639db475SFUJITA Tomonori 		errsts = resp_xdwriteread(SCpnt, lba, num, devip);
2940639db475SFUJITA Tomonori 		break;
2941639db475SFUJITA Tomonori 	default:
2942639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2943639db475SFUJITA Tomonori 			printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
2944639db475SFUJITA Tomonori 			       "supported\n", *cmd);
2945639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2946639db475SFUJITA Tomonori 		if (errsts)
2947639db475SFUJITA Tomonori 			break;	/* Unit attention takes precedence */
2948639db475SFUJITA Tomonori 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
2949639db475SFUJITA Tomonori 		errsts = check_condition_result;
2950639db475SFUJITA Tomonori 		break;
2951639db475SFUJITA Tomonori 	}
2952639db475SFUJITA Tomonori 	return schedule_resp(SCpnt, devip, done, errsts,
2953639db475SFUJITA Tomonori 			     (delay_override ? 0 : scsi_debug_delay));
2954639db475SFUJITA Tomonori }
2955639db475SFUJITA Tomonori 
29569e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
29579e603ca0SFUJITA Tomonori 	.proc_info =		scsi_debug_proc_info,
29589e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
29599e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
29609e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
29619e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
29629e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
29639e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
29649e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
29659e603ca0SFUJITA Tomonori 	.queuecommand =		scsi_debug_queuecommand,
29669e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
29679e603ca0SFUJITA Tomonori 	.eh_bus_reset_handler = scsi_debug_bus_reset,
29689e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
29699e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
29709e603ca0SFUJITA Tomonori 	.bios_param =		scsi_debug_biosparam,
29719e603ca0SFUJITA Tomonori 	.can_queue =		SCSI_DEBUG_CANQUEUE,
29729e603ca0SFUJITA Tomonori 	.this_id =		7,
29739e603ca0SFUJITA Tomonori 	.sg_tablesize =		256,
29749e603ca0SFUJITA Tomonori 	.cmd_per_lun =		16,
29759e603ca0SFUJITA Tomonori 	.max_sectors =		0xffff,
29769e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
29779e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
29789e603ca0SFUJITA Tomonori };
29799e603ca0SFUJITA Tomonori 
29801da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev)
29811da177e4SLinus Torvalds {
29821da177e4SLinus Torvalds         int error = 0;
29831da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
29841da177e4SLinus Torvalds         struct Scsi_Host *hpnt;
29851da177e4SLinus Torvalds 
29861da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
29871da177e4SLinus Torvalds 
29881da177e4SLinus Torvalds         hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
29891da177e4SLinus Torvalds         if (NULL == hpnt) {
29901da177e4SLinus Torvalds                 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
29911da177e4SLinus Torvalds                 error = -ENODEV;
29921da177e4SLinus Torvalds 		return error;
29931da177e4SLinus Torvalds         }
29941da177e4SLinus Torvalds 
29951da177e4SLinus Torvalds         sdbg_host->shost = hpnt;
29961da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
29971da177e4SLinus Torvalds 	if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
29981da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts + 1;
29991da177e4SLinus Torvalds 	else
30001da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts;
3001c65b1445SDouglas Gilbert 	hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;	/* = scsi_debug_max_luns; */
30021da177e4SLinus Torvalds 
30031da177e4SLinus Torvalds         error = scsi_add_host(hpnt, &sdbg_host->dev);
30041da177e4SLinus Torvalds         if (error) {
30051da177e4SLinus Torvalds                 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
30061da177e4SLinus Torvalds                 error = -ENODEV;
30071da177e4SLinus Torvalds 		scsi_host_put(hpnt);
30081da177e4SLinus Torvalds         } else
30091da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
30101da177e4SLinus Torvalds 
30111da177e4SLinus Torvalds 
30121da177e4SLinus Torvalds         return error;
30131da177e4SLinus Torvalds }
30141da177e4SLinus Torvalds 
30151da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev)
30161da177e4SLinus Torvalds {
30171da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
30188b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
30191da177e4SLinus Torvalds 
30201da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
30211da177e4SLinus Torvalds 
30221da177e4SLinus Torvalds 	if (!sdbg_host) {
30231da177e4SLinus Torvalds 		printk(KERN_ERR "%s: Unable to locate host info\n",
30241da177e4SLinus Torvalds 		       __FUNCTION__);
30251da177e4SLinus Torvalds 		return -ENODEV;
30261da177e4SLinus Torvalds 	}
30271da177e4SLinus Torvalds 
30281da177e4SLinus Torvalds         scsi_remove_host(sdbg_host->shost);
30291da177e4SLinus Torvalds 
30308b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
30318b40228fSFUJITA Tomonori 				 dev_list) {
30321da177e4SLinus Torvalds                 list_del(&sdbg_devinfo->dev_list);
30331da177e4SLinus Torvalds                 kfree(sdbg_devinfo);
30341da177e4SLinus Torvalds         }
30351da177e4SLinus Torvalds 
30361da177e4SLinus Torvalds         scsi_host_put(sdbg_host->shost);
30371da177e4SLinus Torvalds         return 0;
30381da177e4SLinus Torvalds }
30391da177e4SLinus Torvalds 
30408dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
30418dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
30421da177e4SLinus Torvalds {
30438dea0d02SFUJITA Tomonori 	return 1;
30448dea0d02SFUJITA Tomonori }
30451da177e4SLinus Torvalds 
30468dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
30478dea0d02SFUJITA Tomonori 	.name = "pseudo",
30488dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
30498dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
30508dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
30518dea0d02SFUJITA Tomonori };
3052