xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision a34c4e98)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
31da177e4SLinus Torvalds  *  Copyright (C) 1992  Eric Youngdale
41da177e4SLinus Torvalds  *  Simulate a host adapter with 2 disks attached.  Do a lot of checking
51da177e4SLinus Torvalds  *  to make sure that we are not getting blocks mixed up, and PANIC if
61da177e4SLinus Torvalds  *  anything out of the ordinary is seen.
71da177e4SLinus Torvalds  * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *  This version is more generic, simulating a variable number of disk
1023183910SDouglas Gilbert  *  (or disk like devices) sharing a common amount of RAM. To be more
1123183910SDouglas Gilbert  *  realistic, the simulated devices have the transport attributes of
1223183910SDouglas Gilbert  *  SAS disks.
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  *
151da177e4SLinus Torvalds  *  For documentation see http://www.torque.net/sg/sdebug26.html
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  *   D. Gilbert (dpg) work for Magneto-Optical device test [20010421]
181da177e4SLinus Torvalds  *   dpg: work for devfs large number of disks [20010809]
191da177e4SLinus Torvalds  *        forked for lk 2.5 series [20011216, 20020101]
201da177e4SLinus Torvalds  *        use vmalloc() more inquiry+mode_sense [20020302]
211da177e4SLinus Torvalds  *        add timers for delayed responses [20020721]
221da177e4SLinus Torvalds  *   Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031]
231da177e4SLinus Torvalds  *   Mike Anderson <andmike@us.ibm.com> sysfs work [20021118]
241da177e4SLinus Torvalds  *   dpg: change style of boot options to "scsi_debug.num_tgts=2" and
251da177e4SLinus Torvalds  *        module options to "modprobe scsi_debug num_tgts=2" [20021221]
261da177e4SLinus Torvalds  */
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds #include <linux/module.h>
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds #include <linux/kernel.h>
311da177e4SLinus Torvalds #include <linux/errno.h>
321da177e4SLinus Torvalds #include <linux/timer.h>
331da177e4SLinus Torvalds #include <linux/types.h>
341da177e4SLinus Torvalds #include <linux/string.h>
351da177e4SLinus Torvalds #include <linux/genhd.h>
361da177e4SLinus Torvalds #include <linux/fs.h>
371da177e4SLinus Torvalds #include <linux/init.h>
381da177e4SLinus Torvalds #include <linux/proc_fs.h>
391da177e4SLinus Torvalds #include <linux/vmalloc.h>
401da177e4SLinus Torvalds #include <linux/moduleparam.h>
41852e034dSJens Axboe #include <linux/scatterlist.h>
421da177e4SLinus Torvalds #include <linux/blkdev.h>
439ff26eefSFUJITA Tomonori 
449ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
459ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
469ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
471da177e4SLinus Torvalds #include <scsi/scsi_host.h>
481da177e4SLinus Torvalds #include <scsi/scsicam.h>
49a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds #include <linux/stat.h>
521da177e4SLinus Torvalds 
531da177e4SLinus Torvalds #include "scsi_logging.h"
541da177e4SLinus Torvalds 
556f3cbf55SDouglas Gilbert #define SCSI_DEBUG_VERSION "1.81"
566f3cbf55SDouglas Gilbert static const char * scsi_debug_version_date = "20070104";
571da177e4SLinus Torvalds 
586f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
59c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
60c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
611da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
62c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
631da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
641da177e4SLinus Torvalds #define ADDR_OUT_OF_RANGE 0x21
651da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
66c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
671da177e4SLinus Torvalds #define POWERON_RESET 0x29
681da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
696f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
70c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
71c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
721da177e4SLinus Torvalds 
736f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
746f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
756f3cbf55SDouglas Gilbert 
761da177e4SLinus Torvalds #define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds /* Default values for driver parameters */
791da177e4SLinus Torvalds #define DEF_NUM_HOST   1
801da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
811da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
821da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
831da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
841da177e4SLinus Torvalds  */
851da177e4SLinus Torvalds #define DEF_DELAY   1
861da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
871da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
881da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
891da177e4SLinus Torvalds #define DEF_OPTS   0
901da177e4SLinus Torvalds #define DEF_SCSI_LEVEL   5    /* INQUIRY, byte2 [5->SPC-3] */
911da177e4SLinus Torvalds #define DEF_PTYPE   0
921da177e4SLinus Torvalds #define DEF_D_SENSE   0
93c65b1445SDouglas Gilbert #define DEF_NO_LUN_0   0
94c65b1445SDouglas Gilbert #define DEF_VIRTUAL_GB   0
9523183910SDouglas Gilbert #define DEF_FAKE_RW	0
9623183910SDouglas Gilbert #define DEF_VPD_USE_HOSTNO 1
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */
991da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE   1
1001da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR   2
1011da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT   4
1021da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR   8
1036f3cbf55SDouglas Gilbert #define SCSI_DEBUG_OPT_TRANSPORT_ERR   16
1041da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
1051da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1061da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1071da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1086f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1096f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1101da177e4SLinus Torvalds  *
1111da177e4SLinus Torvalds  * When "every_nth" < 0 then after "- every_nth" commands:
1121da177e4SLinus Torvalds  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
1131da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
1141da177e4SLinus Torvalds  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
1156f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
1166f3cbf55SDouglas Gilbert  *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
1171da177e4SLinus Torvalds  * This will continue until some other action occurs (e.g. the user
1181da177e4SLinus Torvalds  * writing a new value (other than -1 or 1) to every_nth via sysfs).
1191da177e4SLinus Torvalds  */
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
1221da177e4SLinus Torvalds  * sector on read commands: */
1231da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
1241da177e4SLinus Torvalds 
1251da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
1261da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
1271da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
128c65b1445SDouglas Gilbert #define SAM2_WLUN_REPORT_LUNS 0xc101
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST;
1311da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY;
1321da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
1331da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH;
1341da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS;
1351da177e4SLinus Torvalds static int scsi_debug_num_parts = DEF_NUM_PARTS;
1361da177e4SLinus Torvalds static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
1371da177e4SLinus Torvalds static int scsi_debug_opts = DEF_OPTS;
1381da177e4SLinus Torvalds static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
1391da177e4SLinus Torvalds static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
1401da177e4SLinus Torvalds static int scsi_debug_dsense = DEF_D_SENSE;
141c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
142c65b1445SDouglas Gilbert static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
14323183910SDouglas Gilbert static int scsi_debug_fake_rw = DEF_FAKE_RW;
14423183910SDouglas Gilbert static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds static int scsi_debug_cmnd_count = 0;
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds #define DEV_READONLY(TGT)      (0)
1491da177e4SLinus Torvalds #define DEV_REMOVEABLE(TGT)    (0)
1501da177e4SLinus Torvalds 
151c65b1445SDouglas Gilbert static unsigned int sdebug_store_size;	/* in bytes */
152c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
1531da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
1541da177e4SLinus Torvalds 
1551da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
1561da177e4SLinus Torvalds    may still need them */
1571da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
1581da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
1591da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
1601da177e4SLinus Torvalds 
1611da177e4SLinus Torvalds /* default sector size is 512 bytes, 2**9 bytes */
1621da177e4SLinus Torvalds #define POW2_SECT_SIZE 9
1631da177e4SLinus Torvalds #define SECT_SIZE (1 << POW2_SECT_SIZE)
1641da177e4SLinus Torvalds #define SECT_SIZE_PER(TGT) SECT_SIZE
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4
1671da177e4SLinus Torvalds 
1681da177e4SLinus Torvalds #define SDEBUG_SENSE_LEN 32
1691da177e4SLinus Torvalds 
1709e603ca0SFUJITA Tomonori #define SCSI_DEBUG_CANQUEUE  255
1719e603ca0SFUJITA Tomonori #define SCSI_DEBUG_MAX_CMD_LEN 16
1729e603ca0SFUJITA Tomonori 
1731da177e4SLinus Torvalds struct sdebug_dev_info {
1741da177e4SLinus Torvalds 	struct list_head dev_list;
1751da177e4SLinus Torvalds 	unsigned char sense_buff[SDEBUG_SENSE_LEN];	/* weak nexus */
1761da177e4SLinus Torvalds 	unsigned int channel;
1771da177e4SLinus Torvalds 	unsigned int target;
1781da177e4SLinus Torvalds 	unsigned int lun;
1791da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
180c65b1445SDouglas Gilbert 	unsigned int wlun;
1811da177e4SLinus Torvalds 	char reset;
182c65b1445SDouglas Gilbert 	char stopped;
1831da177e4SLinus Torvalds 	char used;
1841da177e4SLinus Torvalds };
1851da177e4SLinus Torvalds 
1861da177e4SLinus Torvalds struct sdebug_host_info {
1871da177e4SLinus Torvalds 	struct list_head host_list;
1881da177e4SLinus Torvalds 	struct Scsi_Host *shost;
1891da177e4SLinus Torvalds 	struct device dev;
1901da177e4SLinus Torvalds 	struct list_head dev_info_list;
1911da177e4SLinus Torvalds };
1921da177e4SLinus Torvalds 
1931da177e4SLinus Torvalds #define to_sdebug_host(d)	\
1941da177e4SLinus Torvalds 	container_of(d, struct sdebug_host_info, dev)
1951da177e4SLinus Torvalds 
1961da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
1971da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds typedef void (* done_funct_t) (struct scsi_cmnd *);
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds struct sdebug_queued_cmd {
2021da177e4SLinus Torvalds 	int in_use;
2031da177e4SLinus Torvalds 	struct timer_list cmnd_timer;
2041da177e4SLinus Torvalds 	done_funct_t done_funct;
2051da177e4SLinus Torvalds 	struct scsi_cmnd * a_cmnd;
2061da177e4SLinus Torvalds 	int scsi_result;
2071da177e4SLinus Torvalds };
2081da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds static unsigned char * fake_storep;	/* ramdisk storage */
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds static int num_aborts = 0;
2131da177e4SLinus Torvalds static int num_dev_resets = 0;
2141da177e4SLinus Torvalds static int num_bus_resets = 0;
2151da177e4SLinus Torvalds static int num_host_resets = 0;
2161da177e4SLinus Torvalds 
2171da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock);
2181da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
2191da177e4SLinus Torvalds 
2201da177e4SLinus Torvalds static char sdebug_proc_name[] = "scsi_debug";
2211da177e4SLinus Torvalds 
2221da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *);
2231da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *);
2241da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
2251da177e4SLinus Torvalds 
2261da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
2271da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
2281da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
2291da177e4SLinus Torvalds };
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds static const int check_condition_result =
2321da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
2331da177e4SLinus Torvalds 
234c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
235c65b1445SDouglas Gilbert 				    0, 0, 0x2, 0x4b};
236c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
237c65b1445SDouglas Gilbert 			           0, 0, 0x0, 0x0};
238c65b1445SDouglas Gilbert 
2391da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev);
2401da177e4SLinus Torvalds static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
2411da177e4SLinus Torvalds 			    int asc, int asq);
2421da177e4SLinus Torvalds static void stop_all_queued(void);
2431da177e4SLinus Torvalds static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
2441da177e4SLinus Torvalds 
2451da177e4SLinus Torvalds static int sdebug_add_adapter(void);
2461da177e4SLinus Torvalds static void sdebug_remove_adapter(void);
2471da177e4SLinus Torvalds static void sdebug_max_tgts_luns(void);
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds static struct device pseudo_primary;
2501da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
2511da177e4SLinus Torvalds 
2523de9f944SFUJITA Tomonori static void get_data_transfer_info(unsigned char *cmd,
2533de9f944SFUJITA Tomonori 				   unsigned long long *lba, unsigned int *num)
2543de9f944SFUJITA Tomonori {
2553de9f944SFUJITA Tomonori 	int i;
2563de9f944SFUJITA Tomonori 
2573de9f944SFUJITA Tomonori 	switch (*cmd) {
2583de9f944SFUJITA Tomonori 	case WRITE_16:
2593de9f944SFUJITA Tomonori 	case READ_16:
2603de9f944SFUJITA Tomonori 		for (*lba = 0, i = 0; i < 8; ++i) {
2613de9f944SFUJITA Tomonori 			if (i > 0)
2623de9f944SFUJITA Tomonori 				*lba <<= 8;
2633de9f944SFUJITA Tomonori 			*lba += cmd[2 + i];
2643de9f944SFUJITA Tomonori 		}
2653de9f944SFUJITA Tomonori 		*num = cmd[13] + (cmd[12] << 8) +
2663de9f944SFUJITA Tomonori 			(cmd[11] << 16) + (cmd[10] << 24);
2673de9f944SFUJITA Tomonori 		break;
2683de9f944SFUJITA Tomonori 	case WRITE_12:
2693de9f944SFUJITA Tomonori 	case READ_12:
2703de9f944SFUJITA Tomonori 		*lba = cmd[5] + (cmd[4] << 8) +	(cmd[3] << 16) + (cmd[2] << 24);
2713de9f944SFUJITA Tomonori 		*num = cmd[9] + (cmd[8] << 8) +	(cmd[7] << 16) + (cmd[6] << 24);
2723de9f944SFUJITA Tomonori 		break;
2733de9f944SFUJITA Tomonori 	case WRITE_10:
2743de9f944SFUJITA Tomonori 	case READ_10:
275c639d14eSFUJITA Tomonori 	case XDWRITEREAD_10:
2763de9f944SFUJITA Tomonori 		*lba = cmd[5] + (cmd[4] << 8) +	(cmd[3] << 16) + (cmd[2] << 24);
2773de9f944SFUJITA Tomonori 		*num = cmd[8] + (cmd[7] << 8);
2783de9f944SFUJITA Tomonori 		break;
2793de9f944SFUJITA Tomonori 	case WRITE_6:
2803de9f944SFUJITA Tomonori 	case READ_6:
2813de9f944SFUJITA Tomonori 		*lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
2823de9f944SFUJITA Tomonori 		*num = (0 == cmd[4]) ? 256 : cmd[4];
2833de9f944SFUJITA Tomonori 		break;
2843de9f944SFUJITA Tomonori 	default:
2853de9f944SFUJITA Tomonori 		break;
2863de9f944SFUJITA Tomonori 	}
2873de9f944SFUJITA Tomonori }
2881da177e4SLinus Torvalds 
2891da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
2901da177e4SLinus Torvalds {
2911da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2921da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
2931da177e4SLinus Torvalds 	}
2941da177e4SLinus Torvalds 	return -EINVAL;
2951da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
2961da177e4SLinus Torvalds }
2971da177e4SLinus Torvalds 
298c65b1445SDouglas Gilbert static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
299c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
3001da177e4SLinus Torvalds {
3011da177e4SLinus Torvalds 	if (devip->reset) {
3021da177e4SLinus Torvalds 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3031da177e4SLinus Torvalds 			printk(KERN_INFO "scsi_debug: Reporting Unit "
3041da177e4SLinus Torvalds 			       "attention: power on reset\n");
3051da177e4SLinus Torvalds 		devip->reset = 0;
3061da177e4SLinus Torvalds 		mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
3071da177e4SLinus Torvalds 		return check_condition_result;
3081da177e4SLinus Torvalds 	}
309c65b1445SDouglas Gilbert 	if ((0 == reset_only) && devip->stopped) {
310c65b1445SDouglas Gilbert 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
311c65b1445SDouglas Gilbert 			printk(KERN_INFO "scsi_debug: Reporting Not "
312c65b1445SDouglas Gilbert 			       "ready: initializing command required\n");
313c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
314c65b1445SDouglas Gilbert 				0x2);
315c65b1445SDouglas Gilbert 		return check_condition_result;
316c65b1445SDouglas Gilbert 	}
3171da177e4SLinus Torvalds 	return 0;
3181da177e4SLinus Torvalds }
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
3211da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
3221da177e4SLinus Torvalds 				int arr_len)
3231da177e4SLinus Torvalds {
32421a61829SFUJITA Tomonori 	int act_len;
325072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
3261da177e4SLinus Torvalds 
327072d0bb3SFUJITA Tomonori 	if (!sdb->length)
3281da177e4SLinus Torvalds 		return 0;
329072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
3301da177e4SLinus Torvalds 		return (DID_ERROR << 16);
33121a61829SFUJITA Tomonori 
33221a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
33321a61829SFUJITA Tomonori 				      arr, arr_len);
334072d0bb3SFUJITA Tomonori 	if (sdb->resid)
335072d0bb3SFUJITA Tomonori 		sdb->resid -= act_len;
336c65b1445SDouglas Gilbert 	else
33721a61829SFUJITA Tomonori 		sdb->resid = scsi_bufflen(scp) - act_len;
33821a61829SFUJITA Tomonori 
3391da177e4SLinus Torvalds 	return 0;
3401da177e4SLinus Torvalds }
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */
3431da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
34421a61829SFUJITA Tomonori 			       int arr_len)
3451da177e4SLinus Torvalds {
34621a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
3471da177e4SLinus Torvalds 		return 0;
348072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
3491da177e4SLinus Torvalds 		return -1;
35021a61829SFUJITA Tomonori 
35121a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
3521da177e4SLinus Torvalds }
3531da177e4SLinus Torvalds 
3541da177e4SLinus Torvalds 
3551da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux   ";
3561da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug      ";
3571da177e4SLinus Torvalds static const char * inq_product_rev = "0004";
3581da177e4SLinus Torvalds 
3595a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
3605a09e398SHannes Reinecke 			   int target_dev_id, int dev_id_num,
3615a09e398SHannes Reinecke 			   const char * dev_id_str,
362c65b1445SDouglas Gilbert 			   int dev_id_str_len)
3631da177e4SLinus Torvalds {
364c65b1445SDouglas Gilbert 	int num, port_a;
365c65b1445SDouglas Gilbert 	char b[32];
3661da177e4SLinus Torvalds 
367c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
3681da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
3691da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
3701da177e4SLinus Torvalds 	arr[1] = 0x1;
3711da177e4SLinus Torvalds 	arr[2] = 0x0;
3721da177e4SLinus Torvalds 	memcpy(&arr[4], inq_vendor_id, 8);
3731da177e4SLinus Torvalds 	memcpy(&arr[12], inq_product_id, 16);
3741da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
3751da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
3761da177e4SLinus Torvalds 	arr[3] = num;
3771da177e4SLinus Torvalds 	num += 4;
378c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
379c65b1445SDouglas Gilbert 		/* NAA-5, Logical unit identifier (binary) */
380c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* binary (not necessarily sas) */
381c65b1445SDouglas Gilbert 		arr[num++] = 0x3;	/* PIV=0, lu, naa */
382c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
383c65b1445SDouglas Gilbert 		arr[num++] = 0x8;
384c65b1445SDouglas Gilbert 		arr[num++] = 0x53;  /* naa-5 ieee company id=0x333333 (fake) */
385c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
386c65b1445SDouglas Gilbert 		arr[num++] = 0x33;
387c65b1445SDouglas Gilbert 		arr[num++] = 0x30;
388c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 24);
389c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 16) & 0xff;
390c65b1445SDouglas Gilbert 		arr[num++] = (dev_id_num >> 8) & 0xff;
391c65b1445SDouglas Gilbert 		arr[num++] = dev_id_num & 0xff;
392c65b1445SDouglas Gilbert 		/* Target relative port number */
393c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
394c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
395c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
396c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
397c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
398c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
399c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
400c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
401c65b1445SDouglas Gilbert 	}
402c65b1445SDouglas Gilbert 	/* NAA-5, Target port identifier */
403c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
404c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
405c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
406c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
407c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* naa-5, company id=0x222222 (fake) */
408c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
409c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
410c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
411c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
412c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
413c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
414c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
4155a09e398SHannes Reinecke 	/* NAA-5, Target port group identifier */
4165a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
4175a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
4185a09e398SHannes Reinecke 	arr[num++] = 0x0;
4195a09e398SHannes Reinecke 	arr[num++] = 0x4;
4205a09e398SHannes Reinecke 	arr[num++] = 0;
4215a09e398SHannes Reinecke 	arr[num++] = 0;
4225a09e398SHannes Reinecke 	arr[num++] = (port_group_id >> 8) & 0xff;
4235a09e398SHannes Reinecke 	arr[num++] = port_group_id & 0xff;
424c65b1445SDouglas Gilbert 	/* NAA-5, Target device identifier */
425c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
426c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, 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++] = (target_dev_id >> 24);
434c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 16) & 0xff;
435c65b1445SDouglas Gilbert 	arr[num++] = (target_dev_id >> 8) & 0xff;
436c65b1445SDouglas Gilbert 	arr[num++] = target_dev_id & 0xff;
437c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
438c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
439c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
440c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
441c65b1445SDouglas Gilbert 	arr[num++] = 24;
442c65b1445SDouglas Gilbert 	memcpy(arr + num, "naa.52222220", 12);
443c65b1445SDouglas Gilbert 	num += 12;
444c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
445c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
446c65b1445SDouglas Gilbert 	num += 8;
447c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
448c65b1445SDouglas Gilbert 	num += 4;
449c65b1445SDouglas Gilbert 	return num;
450c65b1445SDouglas Gilbert }
451c65b1445SDouglas Gilbert 
452c65b1445SDouglas Gilbert 
453c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
454c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
455c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
456c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
457c65b1445SDouglas Gilbert };
458c65b1445SDouglas Gilbert 
459c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr)
460c65b1445SDouglas Gilbert {
461c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
462c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
463c65b1445SDouglas Gilbert }
464c65b1445SDouglas Gilbert 
465c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr)
466c65b1445SDouglas Gilbert {
467c65b1445SDouglas Gilbert 	int num = 0;
468c65b1445SDouglas Gilbert 	const char * na1 = "https://www.kernel.org/config";
469c65b1445SDouglas Gilbert 	const char * na2 = "http://www.kernel.org/log";
470c65b1445SDouglas Gilbert 	int plen, olen;
471c65b1445SDouglas Gilbert 
472c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
473c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
474c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
475c65b1445SDouglas Gilbert 	olen = strlen(na1);
476c65b1445SDouglas Gilbert 	plen = olen + 1;
477c65b1445SDouglas Gilbert 	if (plen % 4)
478c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
479c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
480c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
481c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
482c65b1445SDouglas Gilbert 	num += plen;
483c65b1445SDouglas Gilbert 
484c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
485c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
486c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
487c65b1445SDouglas Gilbert 	olen = strlen(na2);
488c65b1445SDouglas Gilbert 	plen = olen + 1;
489c65b1445SDouglas Gilbert 	if (plen % 4)
490c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
491c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
492c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
493c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
494c65b1445SDouglas Gilbert 	num += plen;
495c65b1445SDouglas Gilbert 
496c65b1445SDouglas Gilbert 	return num;
497c65b1445SDouglas Gilbert }
498c65b1445SDouglas Gilbert 
499c65b1445SDouglas Gilbert /* SCSI ports VPD page */
500c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
501c65b1445SDouglas Gilbert {
502c65b1445SDouglas Gilbert 	int num = 0;
503c65b1445SDouglas Gilbert 	int port_a, port_b;
504c65b1445SDouglas Gilbert 
505c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
506c65b1445SDouglas Gilbert 	port_b = port_a + 1;
507c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
508c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
509c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
510c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
511c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
512c65b1445SDouglas Gilbert 	num += 6;
513c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
514c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
515c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
516c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
517c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
518c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
519c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
520c65b1445SDouglas Gilbert 	arr[num++] = 0x52;	/* NAA-5, company_id=0x222222 (fake) */
521c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
522c65b1445SDouglas Gilbert 	arr[num++] = 0x22;
523c65b1445SDouglas Gilbert 	arr[num++] = 0x20;
524c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 24);
525c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 16) & 0xff;
526c65b1445SDouglas Gilbert 	arr[num++] = (port_a >> 8) & 0xff;
527c65b1445SDouglas Gilbert 	arr[num++] = port_a & 0xff;
528c65b1445SDouglas Gilbert 
529c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
530c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
531c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
532c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
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 (B) */
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_b >> 24);
547c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 16) & 0xff;
548c65b1445SDouglas Gilbert 	arr[num++] = (port_b >> 8) & 0xff;
549c65b1445SDouglas Gilbert 	arr[num++] = port_b & 0xff;
550c65b1445SDouglas Gilbert 
551c65b1445SDouglas Gilbert 	return num;
552c65b1445SDouglas Gilbert }
553c65b1445SDouglas Gilbert 
554c65b1445SDouglas Gilbert 
555c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
556c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
557c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
558c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
559c65b1445SDouglas Gilbert '1','2','3','4',
560c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
561c65b1445SDouglas Gilbert 0xec,0,0,0,
562c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
563c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
564c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
565c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
566c65b1445SDouglas Gilbert 0x53,0x41,
567c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
568c65b1445SDouglas Gilbert 0x20,0x20,
569c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
570c65b1445SDouglas Gilbert 0x10,0x80,
571c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
572c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
573c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
574c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
575c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
576c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
577c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
578c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
579c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
580c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
581c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
582c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
583c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
584c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
585c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
586c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
587c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
588c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
589c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
590c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
591c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
592c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
593c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
594c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
595c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
596c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
597c65b1445SDouglas Gilbert };
598c65b1445SDouglas Gilbert 
599c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr)
600c65b1445SDouglas Gilbert {
601c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
602c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
603c65b1445SDouglas Gilbert }
604c65b1445SDouglas Gilbert 
605c65b1445SDouglas Gilbert 
606c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
607c65b1445SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4,
608c65b1445SDouglas Gilbert 	0,0,0x4,0,
609c65b1445SDouglas Gilbert 	0,0,0,64,
610c65b1445SDouglas Gilbert };
611c65b1445SDouglas Gilbert 
612c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr)
613c65b1445SDouglas Gilbert {
614c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
615c65b1445SDouglas Gilbert 	if (sdebug_store_sectors > 0x400) {
616c65b1445SDouglas Gilbert 		arr[4] = (sdebug_store_sectors >> 24) & 0xff;
617c65b1445SDouglas Gilbert 		arr[5] = (sdebug_store_sectors >> 16) & 0xff;
618c65b1445SDouglas Gilbert 		arr[6] = (sdebug_store_sectors >> 8) & 0xff;
619c65b1445SDouglas Gilbert 		arr[7] = sdebug_store_sectors & 0xff;
620c65b1445SDouglas Gilbert 	}
621c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
6221da177e4SLinus Torvalds }
6231da177e4SLinus Torvalds 
6241da177e4SLinus Torvalds 
6251da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
626c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
6271da177e4SLinus Torvalds 
6281da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd * scp, int target,
6291da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
6301da177e4SLinus Torvalds {
6311da177e4SLinus Torvalds 	unsigned char pq_pdt;
6325a09e398SHannes Reinecke 	unsigned char * arr;
6331da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
6345a09e398SHannes Reinecke 	int alloc_len, n, ret;
6351da177e4SLinus Torvalds 
6361da177e4SLinus Torvalds 	alloc_len = (cmd[3] << 8) + cmd[4];
6376f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
6386f3cbf55SDouglas Gilbert 	if (! arr)
6396f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
640c65b1445SDouglas Gilbert 	if (devip->wlun)
641c65b1445SDouglas Gilbert 		pq_pdt = 0x1e;	/* present, wlun */
642c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (0 == devip->lun))
643c65b1445SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, no device type */
644c65b1445SDouglas Gilbert 	else
6451da177e4SLinus Torvalds 		pq_pdt = (scsi_debug_ptype & 0x1f);
6461da177e4SLinus Torvalds 	arr[0] = pq_pdt;
6471da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
6481da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
6491da177e4SLinus Torvalds 			       	0);
6505a09e398SHannes Reinecke 		kfree(arr);
6511da177e4SLinus Torvalds 		return check_condition_result;
6521da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
6535a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
654c65b1445SDouglas Gilbert 		char lu_id_str[6];
655c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
6561da177e4SLinus Torvalds 
6575a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
6585a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
65923183910SDouglas Gilbert 		if (0 == scsi_debug_vpd_use_hostno)
66023183910SDouglas Gilbert 			host_no = 0;
661c65b1445SDouglas Gilbert 		lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
662c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
663c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
664c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
665c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
6661da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
667c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
668c65b1445SDouglas Gilbert 			n = 4;
669c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
670c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
671c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
672c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
673c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
674c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
675c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
676c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
677c65b1445SDouglas Gilbert 			arr[n++] = 0x89;  /* ATA information */
678c65b1445SDouglas Gilbert 			arr[n++] = 0xb0;  /* Block limits (SBC) */
679c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
6801da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
681c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
6821da177e4SLinus Torvalds 			arr[3] = len;
683c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
6841da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
685c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
6865a09e398SHannes Reinecke 			arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
6875a09e398SHannes Reinecke 						 target_dev_id, lu_id_num,
6885a09e398SHannes Reinecke 						 lu_id_str, len);
689c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
690c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
691c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_84(&arr[4]);
692c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
693c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
694c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_85(&arr[4]);
695c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
696c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
697c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
698c65b1445SDouglas Gilbert 			arr[4] = 0x0;   /* no protection stuff */
699c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
700c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
701c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
702c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
703c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
704c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
705c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
706c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
707c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
708c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
709c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
710c65b1445SDouglas Gilbert 		} else if (0x89 == cmd[2]) { /* ATA information */
711c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
712c65b1445SDouglas Gilbert 			n = inquiry_evpd_89(&arr[4]);
713c65b1445SDouglas Gilbert 			arr[2] = (n >> 8);
714c65b1445SDouglas Gilbert 			arr[3] = (n & 0xff);
715c65b1445SDouglas Gilbert 		} else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
716c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
717c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_b0(&arr[4]);
7181da177e4SLinus Torvalds 		} else {
7191da177e4SLinus Torvalds 			/* Illegal request, invalid field in cdb */
7201da177e4SLinus Torvalds 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
7211da177e4SLinus Torvalds 					INVALID_FIELD_IN_CDB, 0);
7225a09e398SHannes Reinecke 			kfree(arr);
7231da177e4SLinus Torvalds 			return check_condition_result;
7241da177e4SLinus Torvalds 		}
725c65b1445SDouglas Gilbert 		len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
7265a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
727c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
7285a09e398SHannes Reinecke 		kfree(arr);
7295a09e398SHannes Reinecke 		return ret;
7301da177e4SLinus Torvalds 	}
7311da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
7321da177e4SLinus Torvalds 	arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0;	/* Removable disk */
7331da177e4SLinus Torvalds 	arr[2] = scsi_debug_scsi_level;
7341da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
7351da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
7365a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno)
7375a09e398SHannes Reinecke 		arr[5] = 0x10; /* claim: implicit TGPS */
738c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
7391da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
740c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
7411da177e4SLinus Torvalds 	memcpy(&arr[8], inq_vendor_id, 8);
7421da177e4SLinus Torvalds 	memcpy(&arr[16], inq_product_id, 16);
7431da177e4SLinus Torvalds 	memcpy(&arr[32], inq_product_rev, 4);
7441da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
745c65b1445SDouglas Gilbert 	arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
746c65b1445SDouglas Gilbert 	arr[60] = 0x3; arr[61] = 0x14;  /* SPC-3 ANSI */
747c65b1445SDouglas Gilbert 	n = 62;
7481da177e4SLinus Torvalds 	if (scsi_debug_ptype == 0) {
749c65b1445SDouglas Gilbert 		arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
7501da177e4SLinus Torvalds 	} else if (scsi_debug_ptype == 1) {
751c65b1445SDouglas Gilbert 		arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
7521da177e4SLinus Torvalds 	}
753c65b1445SDouglas Gilbert 	arr[n++] = 0xc; arr[n++] = 0xf;  /* SAS-1.1 rev 10 */
7545a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
7551da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
7565a09e398SHannes Reinecke 	kfree(arr);
7575a09e398SHannes Reinecke 	return ret;
7581da177e4SLinus Torvalds }
7591da177e4SLinus Torvalds 
7601da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp,
7611da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip)
7621da177e4SLinus Torvalds {
7631da177e4SLinus Torvalds 	unsigned char * sbuff;
7641da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
7651da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_SENSE_LEN];
766c65b1445SDouglas Gilbert 	int want_dsense;
7671da177e4SLinus Torvalds 	int len = 18;
7681da177e4SLinus Torvalds 
769c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
7701da177e4SLinus Torvalds 	if (devip->reset == 1)
771c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
772c65b1445SDouglas Gilbert 	want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
7731da177e4SLinus Torvalds 	sbuff = devip->sense_buff;
774c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
775c65b1445SDouglas Gilbert 		if (want_dsense) {
776c65b1445SDouglas Gilbert 			arr[0] = 0x72;
777c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
778c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
779c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
780c65b1445SDouglas Gilbert 		} else {
781c65b1445SDouglas Gilbert 			arr[0] = 0x70;
782c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
783c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
784c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
785c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
786c65b1445SDouglas Gilbert 		}
787c65b1445SDouglas Gilbert 	} else {
788c65b1445SDouglas Gilbert 		memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
7891da177e4SLinus Torvalds 		if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
7901da177e4SLinus Torvalds 			/* DESC bit set and sense_buff in fixed format */
791c65b1445SDouglas Gilbert 			memset(arr, 0, sizeof(arr));
7921da177e4SLinus Torvalds 			arr[0] = 0x72;
7931da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
7941da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
7951da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
7961da177e4SLinus Torvalds 			len = 8;
797c65b1445SDouglas Gilbert 		}
798c65b1445SDouglas Gilbert 	}
799c65b1445SDouglas Gilbert 	mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
8001da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
8011da177e4SLinus Torvalds }
8021da177e4SLinus Torvalds 
803c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp,
804c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
805c65b1445SDouglas Gilbert {
806c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
807c65b1445SDouglas Gilbert 	int power_cond, errsts, start;
808c65b1445SDouglas Gilbert 
809c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
810c65b1445SDouglas Gilbert 		return errsts;
811c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
812c65b1445SDouglas Gilbert 	if (power_cond) {
813c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
814c65b1445SDouglas Gilbert 			       	0);
815c65b1445SDouglas Gilbert 		return check_condition_result;
816c65b1445SDouglas Gilbert 	}
817c65b1445SDouglas Gilbert 	start = cmd[4] & 1;
818c65b1445SDouglas Gilbert 	if (start == devip->stopped)
819c65b1445SDouglas Gilbert 		devip->stopped = !start;
820c65b1445SDouglas Gilbert 	return 0;
821c65b1445SDouglas Gilbert }
822c65b1445SDouglas Gilbert 
8231da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
8241da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp,
8251da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
8261da177e4SLinus Torvalds {
8271da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
828c65b1445SDouglas Gilbert 	unsigned int capac;
8291da177e4SLinus Torvalds 	int errsts;
8301da177e4SLinus Torvalds 
831c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
8321da177e4SLinus Torvalds 		return errsts;
833c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
834c65b1445SDouglas Gilbert 	if (scsi_debug_virtual_gb > 0) {
835c65b1445SDouglas Gilbert 		sdebug_capacity = 2048 * 1024;
836c65b1445SDouglas Gilbert 		sdebug_capacity *= scsi_debug_virtual_gb;
837c65b1445SDouglas Gilbert 	} else
838c65b1445SDouglas Gilbert 		sdebug_capacity = sdebug_store_sectors;
8391da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
840c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
841c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
8421da177e4SLinus Torvalds 		arr[0] = (capac >> 24);
8431da177e4SLinus Torvalds 		arr[1] = (capac >> 16) & 0xff;
8441da177e4SLinus Torvalds 		arr[2] = (capac >> 8) & 0xff;
8451da177e4SLinus Torvalds 		arr[3] = capac & 0xff;
846c65b1445SDouglas Gilbert 	} else {
847c65b1445SDouglas Gilbert 		arr[0] = 0xff;
848c65b1445SDouglas Gilbert 		arr[1] = 0xff;
849c65b1445SDouglas Gilbert 		arr[2] = 0xff;
850c65b1445SDouglas Gilbert 		arr[3] = 0xff;
851c65b1445SDouglas Gilbert 	}
8521da177e4SLinus Torvalds 	arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
8531da177e4SLinus Torvalds 	arr[7] = SECT_SIZE_PER(target) & 0xff;
8541da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
8551da177e4SLinus Torvalds }
8561da177e4SLinus Torvalds 
857c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
858c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp,
859c65b1445SDouglas Gilbert 			  struct sdebug_dev_info * devip)
860c65b1445SDouglas Gilbert {
861c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
862c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
863c65b1445SDouglas Gilbert 	unsigned long long capac;
864c65b1445SDouglas Gilbert 	int errsts, k, alloc_len;
865c65b1445SDouglas Gilbert 
866c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
867c65b1445SDouglas Gilbert 		return errsts;
868c65b1445SDouglas Gilbert 	alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
869c65b1445SDouglas Gilbert 		     + cmd[13]);
870c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
871c65b1445SDouglas Gilbert 	if (scsi_debug_virtual_gb > 0) {
872c65b1445SDouglas Gilbert 		sdebug_capacity = 2048 * 1024;
873c65b1445SDouglas Gilbert 		sdebug_capacity *= scsi_debug_virtual_gb;
874c65b1445SDouglas Gilbert 	} else
875c65b1445SDouglas Gilbert 		sdebug_capacity = sdebug_store_sectors;
876c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
877c65b1445SDouglas Gilbert 	capac = sdebug_capacity - 1;
878c65b1445SDouglas Gilbert 	for (k = 0; k < 8; ++k, capac >>= 8)
879c65b1445SDouglas Gilbert 		arr[7 - k] = capac & 0xff;
880c65b1445SDouglas Gilbert 	arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
881c65b1445SDouglas Gilbert 	arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
882c65b1445SDouglas Gilbert 	arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
883c65b1445SDouglas Gilbert 	arr[11] = SECT_SIZE_PER(target) & 0xff;
884c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
885c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
886c65b1445SDouglas Gilbert }
887c65b1445SDouglas Gilbert 
8885a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
8895a09e398SHannes Reinecke 
8905a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp,
8915a09e398SHannes Reinecke 			      struct sdebug_dev_info * devip)
8925a09e398SHannes Reinecke {
8935a09e398SHannes Reinecke 	unsigned char *cmd = (unsigned char *)scp->cmnd;
8945a09e398SHannes Reinecke 	unsigned char * arr;
8955a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
8965a09e398SHannes Reinecke 	int n, ret, alen, rlen;
8975a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
8985a09e398SHannes Reinecke 
8995a09e398SHannes Reinecke 	alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
9005a09e398SHannes Reinecke 		+ cmd[9]);
9015a09e398SHannes Reinecke 
9026f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
9036f3cbf55SDouglas Gilbert 	if (! arr)
9046f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
9055a09e398SHannes Reinecke 	/*
9065a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
9075a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
9085a09e398SHannes Reinecke 	 * So we create two port groups with one port each
9095a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
9105a09e398SHannes Reinecke 	 */
9115a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
9125a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
9135a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
9145a09e398SHannes Reinecke 	    (devip->channel & 0x7f);
9155a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
9165a09e398SHannes Reinecke 	    (devip->channel & 0x7f) + 0x80;
9175a09e398SHannes Reinecke 
9185a09e398SHannes Reinecke 	/*
9195a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
9205a09e398SHannes Reinecke 	 */
9215a09e398SHannes Reinecke 	n = 4;
9225a09e398SHannes Reinecke 	if (0 == scsi_debug_vpd_use_hostno) {
9235a09e398SHannes Reinecke 	    arr[n++] = host_no % 3; /* Asymm access state */
9245a09e398SHannes Reinecke 	    arr[n++] = 0x0F; /* claim: all states are supported */
9255a09e398SHannes Reinecke 	} else {
9265a09e398SHannes Reinecke 	    arr[n++] = 0x0; /* Active/Optimized path */
9275a09e398SHannes Reinecke 	    arr[n++] = 0x01; /* claim: only support active/optimized paths */
9285a09e398SHannes Reinecke 	}
9295a09e398SHannes Reinecke 	arr[n++] = (port_group_a >> 8) & 0xff;
9305a09e398SHannes Reinecke 	arr[n++] = port_group_a & 0xff;
9315a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
9325a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
9335a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
9345a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
9355a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
9365a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
9375a09e398SHannes Reinecke 	arr[n++] = (port_a >> 8) & 0xff;
9385a09e398SHannes Reinecke 	arr[n++] = port_a & 0xff;
9395a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
9405a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
9415a09e398SHannes Reinecke 	arr[n++] = (port_group_b >> 8) & 0xff;
9425a09e398SHannes Reinecke 	arr[n++] = port_group_b & 0xff;
9435a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
9445a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
9455a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
9465a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
9475a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
9485a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
9495a09e398SHannes Reinecke 	arr[n++] = (port_b >> 8) & 0xff;
9505a09e398SHannes Reinecke 	arr[n++] = port_b & 0xff;
9515a09e398SHannes Reinecke 
9525a09e398SHannes Reinecke 	rlen = n - 4;
9535a09e398SHannes Reinecke 	arr[0] = (rlen >> 24) & 0xff;
9545a09e398SHannes Reinecke 	arr[1] = (rlen >> 16) & 0xff;
9555a09e398SHannes Reinecke 	arr[2] = (rlen >> 8) & 0xff;
9565a09e398SHannes Reinecke 	arr[3] = rlen & 0xff;
9575a09e398SHannes Reinecke 
9585a09e398SHannes Reinecke 	/*
9595a09e398SHannes Reinecke 	 * Return the smallest value of either
9605a09e398SHannes Reinecke 	 * - The allocated length
9615a09e398SHannes Reinecke 	 * - The constructed command length
9625a09e398SHannes Reinecke 	 * - The maximum array size
9635a09e398SHannes Reinecke 	 */
9645a09e398SHannes Reinecke 	rlen = min(alen,n);
9655a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
9665a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
9675a09e398SHannes Reinecke 	kfree(arr);
9685a09e398SHannes Reinecke 	return ret;
9695a09e398SHannes Reinecke }
9705a09e398SHannes Reinecke 
9711da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
9721da177e4SLinus Torvalds 
9731da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
9741da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
9751da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
9761da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
9771da177e4SLinus Torvalds 
9781da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
9791da177e4SLinus Torvalds 	if (1 == pcontrol)
9801da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
9811da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
9821da177e4SLinus Torvalds }
9831da177e4SLinus Torvalds 
9841da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
9851da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
9861da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
9871da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
9881da177e4SLinus Torvalds 
9891da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
9901da177e4SLinus Torvalds 	if (1 == pcontrol)
9911da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
9921da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
9931da177e4SLinus Torvalds }
9941da177e4SLinus Torvalds 
9951da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target)
9961da177e4SLinus Torvalds {       /* Format device page for mode_sense */
9971da177e4SLinus Torvalds         unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
9981da177e4SLinus Torvalds                                      0, 0, 0, 0, 0, 0, 0, 0,
9991da177e4SLinus Torvalds                                      0, 0, 0, 0, 0x40, 0, 0, 0};
10001da177e4SLinus Torvalds 
10011da177e4SLinus Torvalds         memcpy(p, format_pg, sizeof(format_pg));
10021da177e4SLinus Torvalds         p[10] = (sdebug_sectors_per >> 8) & 0xff;
10031da177e4SLinus Torvalds         p[11] = sdebug_sectors_per & 0xff;
10041da177e4SLinus Torvalds         p[12] = (SECT_SIZE >> 8) & 0xff;
10051da177e4SLinus Torvalds         p[13] = SECT_SIZE & 0xff;
10061da177e4SLinus Torvalds         if (DEV_REMOVEABLE(target))
10071da177e4SLinus Torvalds                 p[20] |= 0x20; /* should agree with INQUIRY */
10081da177e4SLinus Torvalds         if (1 == pcontrol)
10091da177e4SLinus Torvalds                 memset(p + 2, 0, sizeof(format_pg) - 2);
10101da177e4SLinus Torvalds         return sizeof(format_pg);
10111da177e4SLinus Torvalds }
10121da177e4SLinus Torvalds 
10131da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
10141da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
10151da177e4SLinus Torvalds 	unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
10161da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
10171da177e4SLinus Torvalds 
10181da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
10191da177e4SLinus Torvalds 	if (1 == pcontrol)
10201da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(caching_pg) - 2);
10211da177e4SLinus Torvalds 	return sizeof(caching_pg);
10221da177e4SLinus Torvalds }
10231da177e4SLinus Torvalds 
10241da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
10251da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
1026c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1027c65b1445SDouglas Gilbert 				        0, 0, 0, 0};
1028c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
10291da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
10301da177e4SLinus Torvalds 
10311da177e4SLinus Torvalds 	if (scsi_debug_dsense)
10321da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
1033c65b1445SDouglas Gilbert 	else
1034c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
10351da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
10361da177e4SLinus Torvalds 	if (1 == pcontrol)
1037c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1038c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1039c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
10401da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
10411da177e4SLinus Torvalds }
10421da177e4SLinus Torvalds 
1043c65b1445SDouglas Gilbert 
10441da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
10451da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
1046c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
10471da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
1048c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1049c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
1050c65b1445SDouglas Gilbert 
10511da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
10521da177e4SLinus Torvalds 	if (1 == pcontrol)
1053c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1054c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1055c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
10561da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
10571da177e4SLinus Torvalds }
10581da177e4SLinus Torvalds 
1059c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1060c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
1061c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1062c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1063c65b1445SDouglas Gilbert 
1064c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1065c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1066c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1067c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
1068c65b1445SDouglas Gilbert }
1069c65b1445SDouglas Gilbert 
1070c65b1445SDouglas Gilbert 
1071c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1072c65b1445SDouglas Gilbert 			      int target_dev_id)
1073c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
1074c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1075c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1076c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1077c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1078c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
1079c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1080c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1081c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1082c65b1445SDouglas Gilbert 		    0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1083c65b1445SDouglas Gilbert 		    0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1084c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
1085c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1086c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1087c65b1445SDouglas Gilbert 		};
1088c65b1445SDouglas Gilbert 	int port_a, port_b;
1089c65b1445SDouglas Gilbert 
1090c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1091c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1092c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1093c65b1445SDouglas Gilbert 	p[20] = (port_a >> 24);
1094c65b1445SDouglas Gilbert 	p[21] = (port_a >> 16) & 0xff;
1095c65b1445SDouglas Gilbert 	p[22] = (port_a >> 8) & 0xff;
1096c65b1445SDouglas Gilbert 	p[23] = port_a & 0xff;
1097c65b1445SDouglas Gilbert 	p[48 + 20] = (port_b >> 24);
1098c65b1445SDouglas Gilbert 	p[48 + 21] = (port_b >> 16) & 0xff;
1099c65b1445SDouglas Gilbert 	p[48 + 22] = (port_b >> 8) & 0xff;
1100c65b1445SDouglas Gilbert 	p[48 + 23] = port_b & 0xff;
1101c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1102c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1103c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
1104c65b1445SDouglas Gilbert }
1105c65b1445SDouglas Gilbert 
1106c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1107c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
1108c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1109c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1110c65b1445SDouglas Gilbert 		};
1111c65b1445SDouglas Gilbert 
1112c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1113c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1114c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1115c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
1116c65b1445SDouglas Gilbert }
1117c65b1445SDouglas Gilbert 
11181da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
11191da177e4SLinus Torvalds 
11201da177e4SLinus Torvalds static int resp_mode_sense(struct scsi_cmnd * scp, int target,
11211da177e4SLinus Torvalds 			   struct sdebug_dev_info * devip)
11221da177e4SLinus Torvalds {
112323183910SDouglas Gilbert 	unsigned char dbd, llbaa;
112423183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
11251da177e4SLinus Torvalds 	unsigned char dev_spec;
112623183910SDouglas Gilbert 	int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
11271da177e4SLinus Torvalds 	unsigned char * ap;
11281da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
11291da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
11301da177e4SLinus Torvalds 
1131c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
11321da177e4SLinus Torvalds 		return errsts;
113323183910SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);
11341da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
11351da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
11361da177e4SLinus Torvalds 	subpcode = cmd[3];
11371da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
113823183910SDouglas Gilbert 	llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
113923183910SDouglas Gilbert 	if ((0 == scsi_debug_ptype) && (0 == dbd))
114023183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
114123183910SDouglas Gilbert 	else
114223183910SDouglas Gilbert 		bd_len = 0;
11431da177e4SLinus Torvalds 	alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
11441da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
11451da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
11461da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
11471da177e4SLinus Torvalds 			       	0);
11481da177e4SLinus Torvalds 		return check_condition_result;
11491da177e4SLinus Torvalds 	}
1150c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1151c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
115223183910SDouglas Gilbert 	/* set DPOFUA bit for disks */
115323183910SDouglas Gilbert 	if (0 == scsi_debug_ptype)
115423183910SDouglas Gilbert 		dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
115523183910SDouglas Gilbert 	else
115623183910SDouglas Gilbert 		dev_spec = 0x0;
11571da177e4SLinus Torvalds 	if (msense_6) {
11581da177e4SLinus Torvalds 		arr[2] = dev_spec;
115923183910SDouglas Gilbert 		arr[3] = bd_len;
11601da177e4SLinus Torvalds 		offset = 4;
11611da177e4SLinus Torvalds 	} else {
11621da177e4SLinus Torvalds 		arr[3] = dev_spec;
116323183910SDouglas Gilbert 		if (16 == bd_len)
116423183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
116523183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
11661da177e4SLinus Torvalds 		offset = 8;
11671da177e4SLinus Torvalds 	}
11681da177e4SLinus Torvalds 	ap = arr + offset;
116923183910SDouglas Gilbert 	if ((bd_len > 0) && (0 == sdebug_capacity)) {
117023183910SDouglas Gilbert 		if (scsi_debug_virtual_gb > 0) {
117123183910SDouglas Gilbert 			sdebug_capacity = 2048 * 1024;
117223183910SDouglas Gilbert 			sdebug_capacity *= scsi_debug_virtual_gb;
117323183910SDouglas Gilbert 		} else
117423183910SDouglas Gilbert 			sdebug_capacity = sdebug_store_sectors;
117523183910SDouglas Gilbert 	}
117623183910SDouglas Gilbert 	if (8 == bd_len) {
117723183910SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe) {
117823183910SDouglas Gilbert 			ap[0] = 0xff;
117923183910SDouglas Gilbert 			ap[1] = 0xff;
118023183910SDouglas Gilbert 			ap[2] = 0xff;
118123183910SDouglas Gilbert 			ap[3] = 0xff;
118223183910SDouglas Gilbert 		} else {
118323183910SDouglas Gilbert 			ap[0] = (sdebug_capacity >> 24) & 0xff;
118423183910SDouglas Gilbert 			ap[1] = (sdebug_capacity >> 16) & 0xff;
118523183910SDouglas Gilbert 			ap[2] = (sdebug_capacity >> 8) & 0xff;
118623183910SDouglas Gilbert 			ap[3] = sdebug_capacity & 0xff;
118723183910SDouglas Gilbert 		}
118823183910SDouglas Gilbert         	ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
118923183910SDouglas Gilbert         	ap[7] = SECT_SIZE_PER(target) & 0xff;
119023183910SDouglas Gilbert 		offset += bd_len;
119123183910SDouglas Gilbert 		ap = arr + offset;
119223183910SDouglas Gilbert 	} else if (16 == bd_len) {
119323183910SDouglas Gilbert 		unsigned long long capac = sdebug_capacity;
119423183910SDouglas Gilbert 
119523183910SDouglas Gilbert         	for (k = 0; k < 8; ++k, capac >>= 8)
119623183910SDouglas Gilbert                 	ap[7 - k] = capac & 0xff;
119723183910SDouglas Gilbert         	ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
119823183910SDouglas Gilbert         	ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
119923183910SDouglas Gilbert         	ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
120023183910SDouglas Gilbert         	ap[15] = SECT_SIZE_PER(target) & 0xff;
120123183910SDouglas Gilbert 		offset += bd_len;
120223183910SDouglas Gilbert 		ap = arr + offset;
120323183910SDouglas Gilbert 	}
12041da177e4SLinus Torvalds 
1205c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1206c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
12071da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
12081da177e4SLinus Torvalds 			       	0);
12091da177e4SLinus Torvalds 		return check_condition_result;
12101da177e4SLinus Torvalds 	}
12111da177e4SLinus Torvalds 	switch (pcode) {
12121da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
12131da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
12141da177e4SLinus Torvalds 		offset += len;
12151da177e4SLinus Torvalds 		break;
12161da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
12171da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
12181da177e4SLinus Torvalds 		offset += len;
12191da177e4SLinus Torvalds 		break;
12201da177e4SLinus Torvalds         case 0x3:       /* Format device page, direct access */
12211da177e4SLinus Torvalds                 len = resp_format_pg(ap, pcontrol, target);
12221da177e4SLinus Torvalds                 offset += len;
12231da177e4SLinus Torvalds                 break;
12241da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
12251da177e4SLinus Torvalds 		len = resp_caching_pg(ap, pcontrol, target);
12261da177e4SLinus Torvalds 		offset += len;
12271da177e4SLinus Torvalds 		break;
12281da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
12291da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
12301da177e4SLinus Torvalds 		offset += len;
12311da177e4SLinus Torvalds 		break;
1232c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
1233c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
1234c65b1445SDouglas Gilbert 		        mk_sense_buffer(devip, ILLEGAL_REQUEST,
1235c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1236c65b1445SDouglas Gilbert 			return check_condition_result;
1237c65b1445SDouglas Gilbert 	        }
1238c65b1445SDouglas Gilbert 		len = 0;
1239c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
1240c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1241c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
1242c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1243c65b1445SDouglas Gilbert 						  target_dev_id);
1244c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
1245c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
1246c65b1445SDouglas Gilbert 		offset += len;
1247c65b1445SDouglas Gilbert 		break;
12481da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
12491da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
12501da177e4SLinus Torvalds 		offset += len;
12511da177e4SLinus Torvalds 		break;
12521da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
1253c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
12541da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
12551da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
12561da177e4SLinus Torvalds 			len += resp_format_pg(ap + len, pcontrol, target);
12571da177e4SLinus Torvalds 			len += resp_caching_pg(ap + len, pcontrol, target);
12581da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1259c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1260c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
1261c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1262c65b1445SDouglas Gilbert 						  target, target_dev_id);
1263c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
1264c65b1445SDouglas Gilbert 			}
12651da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
1266c65b1445SDouglas Gilbert 		} else {
1267c65b1445SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
1268c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1269c65b1445SDouglas Gilbert 			return check_condition_result;
1270c65b1445SDouglas Gilbert                 }
12711da177e4SLinus Torvalds 		offset += len;
12721da177e4SLinus Torvalds 		break;
12731da177e4SLinus Torvalds 	default:
12741da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
12751da177e4SLinus Torvalds 			       	0);
12761da177e4SLinus Torvalds 		return check_condition_result;
12771da177e4SLinus Torvalds 	}
12781da177e4SLinus Torvalds 	if (msense_6)
12791da177e4SLinus Torvalds 		arr[0] = offset - 1;
12801da177e4SLinus Torvalds 	else {
12811da177e4SLinus Torvalds 		arr[0] = ((offset - 2) >> 8) & 0xff;
12821da177e4SLinus Torvalds 		arr[1] = (offset - 2) & 0xff;
12831da177e4SLinus Torvalds 	}
12841da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
12851da177e4SLinus Torvalds }
12861da177e4SLinus Torvalds 
1287c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
1288c65b1445SDouglas Gilbert 
1289c65b1445SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1290c65b1445SDouglas Gilbert 			    struct sdebug_dev_info * devip)
1291c65b1445SDouglas Gilbert {
1292c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1293c65b1445SDouglas Gilbert 	int param_len, res, errsts, mpage;
1294c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1295c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1296c65b1445SDouglas Gilbert 
1297c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1298c65b1445SDouglas Gilbert 		return errsts;
1299c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1300c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
1301c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
1302c65b1445SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1303c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1304c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1305c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
1306c65b1445SDouglas Gilbert 		return check_condition_result;
1307c65b1445SDouglas Gilbert 	}
1308c65b1445SDouglas Gilbert         res = fetch_to_dev_buffer(scp, arr, param_len);
1309c65b1445SDouglas Gilbert         if (-1 == res)
1310c65b1445SDouglas Gilbert                 return (DID_ERROR << 16);
1311c65b1445SDouglas Gilbert         else if ((res < param_len) &&
1312c65b1445SDouglas Gilbert                  (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1313c65b1445SDouglas Gilbert                 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1314c65b1445SDouglas Gilbert                        " IO sent=%d bytes\n", param_len, res);
1315c65b1445SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1316c65b1445SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
131723183910SDouglas Gilbert 	if (md_len > 2) {
1318c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1319c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_PARAM_LIST, 0);
1320c65b1445SDouglas Gilbert 		return check_condition_result;
1321c65b1445SDouglas Gilbert 	}
1322c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
1323c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
1324c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
1325c65b1445SDouglas Gilbert 	if (ps) {
1326c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1327c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_PARAM_LIST, 0);
1328c65b1445SDouglas Gilbert 		return check_condition_result;
1329c65b1445SDouglas Gilbert 	}
1330c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
1331c65b1445SDouglas Gilbert 	pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1332c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
1333c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
1334c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1335c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
1336c65b1445SDouglas Gilbert 		return check_condition_result;
1337c65b1445SDouglas Gilbert 	}
1338c65b1445SDouglas Gilbert 	switch (mpage) {
1339c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
1340c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
1341c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
1342c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
1343c65b1445SDouglas Gilbert 			scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1344c65b1445SDouglas Gilbert 			return 0;
1345c65b1445SDouglas Gilbert 		}
1346c65b1445SDouglas Gilbert 		break;
1347c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
1348c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
1349c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
1350c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
1351c65b1445SDouglas Gilbert 			return 0;
1352c65b1445SDouglas Gilbert 		}
1353c65b1445SDouglas Gilbert 		break;
1354c65b1445SDouglas Gilbert 	default:
1355c65b1445SDouglas Gilbert 		break;
1356c65b1445SDouglas Gilbert 	}
1357c65b1445SDouglas Gilbert 	mk_sense_buffer(devip, ILLEGAL_REQUEST,
1358c65b1445SDouglas Gilbert 			INVALID_FIELD_IN_PARAM_LIST, 0);
1359c65b1445SDouglas Gilbert 	return check_condition_result;
1360c65b1445SDouglas Gilbert }
1361c65b1445SDouglas Gilbert 
1362c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr)
1363c65b1445SDouglas Gilbert {
1364c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1365c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
1366c65b1445SDouglas Gilbert 		};
1367c65b1445SDouglas Gilbert 
1368c65b1445SDouglas Gilbert         memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1369c65b1445SDouglas Gilbert         return sizeof(temp_l_pg);
1370c65b1445SDouglas Gilbert }
1371c65b1445SDouglas Gilbert 
1372c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr)
1373c65b1445SDouglas Gilbert {
1374c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1375c65b1445SDouglas Gilbert 		};
1376c65b1445SDouglas Gilbert 
1377c65b1445SDouglas Gilbert         memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1378c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
1379c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
1380c65b1445SDouglas Gilbert 		arr[5] = 0xff;
1381c65b1445SDouglas Gilbert 	}
1382c65b1445SDouglas Gilbert         return sizeof(ie_l_pg);
1383c65b1445SDouglas Gilbert }
1384c65b1445SDouglas Gilbert 
1385c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
1386c65b1445SDouglas Gilbert 
1387c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp,
1388c65b1445SDouglas Gilbert                           struct sdebug_dev_info * devip)
1389c65b1445SDouglas Gilbert {
139023183910SDouglas Gilbert 	int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
1391c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1392c65b1445SDouglas Gilbert 	unsigned char *cmd = (unsigned char *)scp->cmnd;
1393c65b1445SDouglas Gilbert 
1394c65b1445SDouglas Gilbert 	if ((errsts = check_readiness(scp, 1, devip)))
1395c65b1445SDouglas Gilbert 		return errsts;
1396c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1397c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
1398c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
1399c65b1445SDouglas Gilbert 	if (ppc || sp) {
1400c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
1401c65b1445SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
1402c65b1445SDouglas Gilbert 		return check_condition_result;
1403c65b1445SDouglas Gilbert 	}
1404c65b1445SDouglas Gilbert 	pcontrol = (cmd[2] & 0xc0) >> 6;
1405c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
140623183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
1407c65b1445SDouglas Gilbert 	alloc_len = (cmd[7] << 8) + cmd[8];
1408c65b1445SDouglas Gilbert 	arr[0] = pcode;
140923183910SDouglas Gilbert 	if (0 == subpcode) {
1410c65b1445SDouglas Gilbert 		switch (pcode) {
1411c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
1412c65b1445SDouglas Gilbert 			n = 4;
1413c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
1414c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
1415c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
1416c65b1445SDouglas Gilbert 			arr[3] = n - 4;
1417c65b1445SDouglas Gilbert 			break;
1418c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
1419c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
1420c65b1445SDouglas Gilbert 			break;
1421c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
1422c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
1423c65b1445SDouglas Gilbert 			break;
1424c65b1445SDouglas Gilbert 		default:
1425c65b1445SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
1426c65b1445SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
1427c65b1445SDouglas Gilbert 			return check_condition_result;
1428c65b1445SDouglas Gilbert 		}
142923183910SDouglas Gilbert 	} else if (0xff == subpcode) {
143023183910SDouglas Gilbert 		arr[0] |= 0x40;
143123183910SDouglas Gilbert 		arr[1] = subpcode;
143223183910SDouglas Gilbert 		switch (pcode) {
143323183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
143423183910SDouglas Gilbert 			n = 4;
143523183910SDouglas Gilbert 			arr[n++] = 0x0;
143623183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
143723183910SDouglas Gilbert 			arr[n++] = 0x0;
143823183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
143923183910SDouglas Gilbert 			arr[n++] = 0xd;
144023183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
144123183910SDouglas Gilbert 			arr[n++] = 0x2f;
144223183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
144323183910SDouglas Gilbert 			arr[3] = n - 4;
144423183910SDouglas Gilbert 			break;
144523183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
144623183910SDouglas Gilbert 			n = 4;
144723183910SDouglas Gilbert 			arr[n++] = 0xd;
144823183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
144923183910SDouglas Gilbert 			arr[3] = n - 4;
145023183910SDouglas Gilbert 			break;
145123183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
145223183910SDouglas Gilbert 			n = 4;
145323183910SDouglas Gilbert 			arr[n++] = 0x2f;
145423183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
145523183910SDouglas Gilbert 			arr[3] = n - 4;
145623183910SDouglas Gilbert 			break;
145723183910SDouglas Gilbert 		default:
145823183910SDouglas Gilbert 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
145923183910SDouglas Gilbert 					INVALID_FIELD_IN_CDB, 0);
146023183910SDouglas Gilbert 			return check_condition_result;
146123183910SDouglas Gilbert 		}
146223183910SDouglas Gilbert 	} else {
146323183910SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST,
146423183910SDouglas Gilbert 				INVALID_FIELD_IN_CDB, 0);
146523183910SDouglas Gilbert 		return check_condition_result;
146623183910SDouglas Gilbert 	}
1467c65b1445SDouglas Gilbert 	len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1468c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1469c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
1470c65b1445SDouglas Gilbert }
1471c65b1445SDouglas Gilbert 
1472c65b1445SDouglas Gilbert static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
1473c65b1445SDouglas Gilbert 		     unsigned int num, struct sdebug_dev_info * devip)
14741da177e4SLinus Torvalds {
14751da177e4SLinus Torvalds 	unsigned long iflags;
1476c65b1445SDouglas Gilbert 	unsigned int block, from_bottom;
1477c65b1445SDouglas Gilbert 	unsigned long long u;
14781da177e4SLinus Torvalds 	int ret;
14791da177e4SLinus Torvalds 
1480c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
14811da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
14821da177e4SLinus Torvalds 				0);
14831da177e4SLinus Torvalds 		return check_condition_result;
14841da177e4SLinus Torvalds 	}
1485c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
1486c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
1487c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1488c65b1445SDouglas Gilbert 				0);
1489c65b1445SDouglas Gilbert 		return check_condition_result;
1490c65b1445SDouglas Gilbert 	}
14911da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
1492c65b1445SDouglas Gilbert 	    (lba <= OPT_MEDIUM_ERR_ADDR) &&
1493c65b1445SDouglas Gilbert 	    ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1494c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
14951da177e4SLinus Torvalds 		mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
14961da177e4SLinus Torvalds 				0);
1497c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
1498c65b1445SDouglas Gilbert 		if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1499c65b1445SDouglas Gilbert 			devip->sense_buff[0] |= 0x80;	/* Valid bit */
1500c65b1445SDouglas Gilbert 			ret = OPT_MEDIUM_ERR_ADDR;
1501c65b1445SDouglas Gilbert 			devip->sense_buff[3] = (ret >> 24) & 0xff;
1502c65b1445SDouglas Gilbert 			devip->sense_buff[4] = (ret >> 16) & 0xff;
1503c65b1445SDouglas Gilbert 			devip->sense_buff[5] = (ret >> 8) & 0xff;
1504c65b1445SDouglas Gilbert 			devip->sense_buff[6] = ret & 0xff;
1505c65b1445SDouglas Gilbert 		}
15061da177e4SLinus Torvalds 		return check_condition_result;
15071da177e4SLinus Torvalds 	}
15081da177e4SLinus Torvalds 	read_lock_irqsave(&atomic_rw, iflags);
1509c65b1445SDouglas Gilbert 	if ((lba + num) <= sdebug_store_sectors)
1510c65b1445SDouglas Gilbert 		ret = fill_from_dev_buffer(SCpnt,
1511c65b1445SDouglas Gilbert 					   fake_storep + (lba * SECT_SIZE),
15121da177e4SLinus Torvalds 			   		   num * SECT_SIZE);
1513c65b1445SDouglas Gilbert 	else {
1514c65b1445SDouglas Gilbert 		/* modulo when one arg is 64 bits needs do_div() */
1515c65b1445SDouglas Gilbert 		u = lba;
1516c65b1445SDouglas Gilbert 		block = do_div(u, sdebug_store_sectors);
1517c65b1445SDouglas Gilbert 		from_bottom = 0;
1518c65b1445SDouglas Gilbert 		if ((block + num) > sdebug_store_sectors)
1519c65b1445SDouglas Gilbert 			from_bottom = (block + num) - sdebug_store_sectors;
1520c65b1445SDouglas Gilbert 		ret = fill_from_dev_buffer(SCpnt,
1521c65b1445SDouglas Gilbert 					   fake_storep + (block * SECT_SIZE),
1522c65b1445SDouglas Gilbert 			   		   (num - from_bottom) * SECT_SIZE);
1523c65b1445SDouglas Gilbert 		if ((0 == ret) && (from_bottom > 0))
1524c65b1445SDouglas Gilbert 			ret = fill_from_dev_buffer(SCpnt, fake_storep,
1525c65b1445SDouglas Gilbert 						   from_bottom * SECT_SIZE);
1526c65b1445SDouglas Gilbert 	}
15271da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
15281da177e4SLinus Torvalds 	return ret;
15291da177e4SLinus Torvalds }
15301da177e4SLinus Torvalds 
1531c65b1445SDouglas Gilbert static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
1532c65b1445SDouglas Gilbert 		      unsigned int num, struct sdebug_dev_info * devip)
15331da177e4SLinus Torvalds {
15341da177e4SLinus Torvalds 	unsigned long iflags;
1535c65b1445SDouglas Gilbert 	unsigned int block, to_bottom;
1536c65b1445SDouglas Gilbert 	unsigned long long u;
15371da177e4SLinus Torvalds 	int res;
15381da177e4SLinus Torvalds 
1539c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
15401da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
15411da177e4SLinus Torvalds 			       	0);
15421da177e4SLinus Torvalds 		return check_condition_result;
15431da177e4SLinus Torvalds 	}
1544c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
1545c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
1546c65b1445SDouglas Gilbert 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1547c65b1445SDouglas Gilbert 				0);
1548c65b1445SDouglas Gilbert 		return check_condition_result;
1549c65b1445SDouglas Gilbert 	}
15501da177e4SLinus Torvalds 
15511da177e4SLinus Torvalds 	write_lock_irqsave(&atomic_rw, iflags);
1552c65b1445SDouglas Gilbert 	if ((lba + num) <= sdebug_store_sectors)
1553c65b1445SDouglas Gilbert 		res = fetch_to_dev_buffer(SCpnt,
1554c65b1445SDouglas Gilbert 					  fake_storep + (lba * SECT_SIZE),
15551da177e4SLinus Torvalds 			   		  num * SECT_SIZE);
1556c65b1445SDouglas Gilbert 	else {
1557c65b1445SDouglas Gilbert 		/* modulo when one arg is 64 bits needs do_div() */
1558c65b1445SDouglas Gilbert 		u = lba;
1559c65b1445SDouglas Gilbert 		block = do_div(u, sdebug_store_sectors);
1560c65b1445SDouglas Gilbert 		to_bottom = 0;
1561c65b1445SDouglas Gilbert 		if ((block + num) > sdebug_store_sectors)
1562c65b1445SDouglas Gilbert 			to_bottom = (block + num) - sdebug_store_sectors;
1563c65b1445SDouglas Gilbert 		res = fetch_to_dev_buffer(SCpnt,
1564c65b1445SDouglas Gilbert 					  fake_storep + (block * SECT_SIZE),
1565c65b1445SDouglas Gilbert 			   		  (num - to_bottom) * SECT_SIZE);
1566c65b1445SDouglas Gilbert 		if ((0 == res) && (to_bottom > 0))
1567c65b1445SDouglas Gilbert 			res = fetch_to_dev_buffer(SCpnt, fake_storep,
1568c65b1445SDouglas Gilbert 						  to_bottom * SECT_SIZE);
1569c65b1445SDouglas Gilbert 	}
15701da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
15711da177e4SLinus Torvalds 	if (-1 == res)
15721da177e4SLinus Torvalds 		return (DID_ERROR << 16);
15731da177e4SLinus Torvalds 	else if ((res < (num * SECT_SIZE)) &&
15741da177e4SLinus Torvalds 		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1575c65b1445SDouglas Gilbert 		printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
15761da177e4SLinus Torvalds 		       " IO sent=%d bytes\n", num * SECT_SIZE, res);
15771da177e4SLinus Torvalds 	return 0;
15781da177e4SLinus Torvalds }
15791da177e4SLinus Torvalds 
1580c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256
15811da177e4SLinus Torvalds 
15821da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp,
15831da177e4SLinus Torvalds 			    struct sdebug_dev_info * devip)
15841da177e4SLinus Torvalds {
15851da177e4SLinus Torvalds 	unsigned int alloc_len;
1586c65b1445SDouglas Gilbert 	int lun_cnt, i, upper, num, n, wlun, lun;
15871da177e4SLinus Torvalds 	unsigned char *cmd = (unsigned char *)scp->cmnd;
15881da177e4SLinus Torvalds 	int select_report = (int)cmd[2];
15891da177e4SLinus Torvalds 	struct scsi_lun *one_lun;
15901da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_RLUN_ARR_SZ];
1591c65b1445SDouglas Gilbert 	unsigned char * max_addr;
15921da177e4SLinus Torvalds 
15931da177e4SLinus Torvalds 	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
1594c65b1445SDouglas Gilbert 	if ((alloc_len < 4) || (select_report > 2)) {
15951da177e4SLinus Torvalds 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
15961da177e4SLinus Torvalds 			       	0);
15971da177e4SLinus Torvalds 		return check_condition_result;
15981da177e4SLinus Torvalds 	}
15991da177e4SLinus Torvalds 	/* can produce response with up to 16k luns (lun 0 to lun 16383) */
16001da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
16011da177e4SLinus Torvalds 	lun_cnt = scsi_debug_max_luns;
1602c65b1445SDouglas Gilbert 	if (1 == select_report)
1603c65b1445SDouglas Gilbert 		lun_cnt = 0;
1604c65b1445SDouglas Gilbert 	else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1605c65b1445SDouglas Gilbert 		--lun_cnt;
1606c65b1445SDouglas Gilbert 	wlun = (select_report > 0) ? 1 : 0;
1607c65b1445SDouglas Gilbert 	num = lun_cnt + wlun;
1608c65b1445SDouglas Gilbert 	arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1609c65b1445SDouglas Gilbert 	arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1610c65b1445SDouglas Gilbert 	n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1611c65b1445SDouglas Gilbert 			    sizeof(struct scsi_lun)), num);
1612c65b1445SDouglas Gilbert 	if (n < num) {
1613c65b1445SDouglas Gilbert 		wlun = 0;
1614c65b1445SDouglas Gilbert 		lun_cnt = n;
1615c65b1445SDouglas Gilbert 	}
16161da177e4SLinus Torvalds 	one_lun = (struct scsi_lun *) &arr[8];
1617c65b1445SDouglas Gilbert 	max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1618c65b1445SDouglas Gilbert 	for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1619c65b1445SDouglas Gilbert              ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1620c65b1445SDouglas Gilbert 	     i++, lun++) {
1621c65b1445SDouglas Gilbert 		upper = (lun >> 8) & 0x3f;
16221da177e4SLinus Torvalds 		if (upper)
16231da177e4SLinus Torvalds 			one_lun[i].scsi_lun[0] =
16241da177e4SLinus Torvalds 			    (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
1625c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = lun & 0xff;
16261da177e4SLinus Torvalds 	}
1627c65b1445SDouglas Gilbert 	if (wlun) {
1628c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1629c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1630c65b1445SDouglas Gilbert 		i++;
1631c65b1445SDouglas Gilbert 	}
1632c65b1445SDouglas Gilbert 	alloc_len = (unsigned char *)(one_lun + i) - arr;
16331da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr,
16341da177e4SLinus Torvalds 				    min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
16351da177e4SLinus Torvalds }
16361da177e4SLinus Torvalds 
1637c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
1638c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
1639c639d14eSFUJITA Tomonori {
1640c639d14eSFUJITA Tomonori 	int i, j, ret = -1;
1641c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
1642c639d14eSFUJITA Tomonori 	unsigned int offset;
1643c639d14eSFUJITA Tomonori 	struct scatterlist *sg;
1644c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
1645c639d14eSFUJITA Tomonori 
1646c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
1647c639d14eSFUJITA Tomonori 	buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
1648c639d14eSFUJITA Tomonori 	if (!buf)
1649c639d14eSFUJITA Tomonori 		return ret;
1650c639d14eSFUJITA Tomonori 
165121a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
1652c639d14eSFUJITA Tomonori 
1653c639d14eSFUJITA Tomonori 	offset = 0;
1654c639d14eSFUJITA Tomonori 	for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
1655c639d14eSFUJITA Tomonori 		kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1656c639d14eSFUJITA Tomonori 		if (!kaddr)
1657c639d14eSFUJITA Tomonori 			goto out;
1658c639d14eSFUJITA Tomonori 
1659c639d14eSFUJITA Tomonori 		for (j = 0; j < sg->length; j++)
1660c639d14eSFUJITA Tomonori 			*(kaddr + sg->offset + j) ^= *(buf + offset + j);
1661c639d14eSFUJITA Tomonori 
1662c639d14eSFUJITA Tomonori 		offset += sg->length;
1663c639d14eSFUJITA Tomonori 		kunmap_atomic(kaddr, KM_USER0);
1664c639d14eSFUJITA Tomonori 	}
1665c639d14eSFUJITA Tomonori 	ret = 0;
1666c639d14eSFUJITA Tomonori out:
1667c639d14eSFUJITA Tomonori 	kfree(buf);
1668c639d14eSFUJITA Tomonori 
1669c639d14eSFUJITA Tomonori 	return ret;
1670c639d14eSFUJITA Tomonori }
1671c639d14eSFUJITA Tomonori 
16721da177e4SLinus Torvalds /* When timer goes off this function is called. */
16731da177e4SLinus Torvalds static void timer_intr_handler(unsigned long indx)
16741da177e4SLinus Torvalds {
16751da177e4SLinus Torvalds 	struct sdebug_queued_cmd * sqcp;
16761da177e4SLinus Torvalds 	unsigned long iflags;
16771da177e4SLinus Torvalds 
16781da177e4SLinus Torvalds 	if (indx >= SCSI_DEBUG_CANQUEUE) {
16791da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
16801da177e4SLinus Torvalds 		       "large\n");
16811da177e4SLinus Torvalds 		return;
16821da177e4SLinus Torvalds 	}
16831da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
16841da177e4SLinus Torvalds 	sqcp = &queued_arr[(int)indx];
16851da177e4SLinus Torvalds 	if (! sqcp->in_use) {
16861da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
16871da177e4SLinus Torvalds 		       "interrupt\n");
16881da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
16891da177e4SLinus Torvalds 		return;
16901da177e4SLinus Torvalds 	}
16911da177e4SLinus Torvalds 	sqcp->in_use = 0;
16921da177e4SLinus Torvalds 	if (sqcp->done_funct) {
16931da177e4SLinus Torvalds 		sqcp->a_cmnd->result = sqcp->scsi_result;
16941da177e4SLinus Torvalds 		sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
16951da177e4SLinus Torvalds 	}
16961da177e4SLinus Torvalds 	sqcp->done_funct = NULL;
16971da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
16981da177e4SLinus Torvalds }
16991da177e4SLinus Torvalds 
17001da177e4SLinus Torvalds static int scsi_debug_slave_alloc(struct scsi_device * sdp)
17011da177e4SLinus Torvalds {
17021da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1703c65b1445SDouglas Gilbert 		printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
1704c65b1445SDouglas Gilbert 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
1705c639d14eSFUJITA Tomonori 	set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags);
17061da177e4SLinus Torvalds 	return 0;
17071da177e4SLinus Torvalds }
17081da177e4SLinus Torvalds 
17091da177e4SLinus Torvalds static int scsi_debug_slave_configure(struct scsi_device * sdp)
17101da177e4SLinus Torvalds {
17111da177e4SLinus Torvalds 	struct sdebug_dev_info * devip;
17121da177e4SLinus Torvalds 
17131da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1714c65b1445SDouglas Gilbert 		printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
1715c65b1445SDouglas Gilbert 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
17161da177e4SLinus Torvalds 	if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
17171da177e4SLinus Torvalds 		sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
17181da177e4SLinus Torvalds 	devip = devInfoReg(sdp);
17196f3cbf55SDouglas Gilbert 	if (NULL == devip)
17206f3cbf55SDouglas Gilbert 		return 1;	/* no resources, will be marked offline */
17211da177e4SLinus Torvalds 	sdp->hostdata = devip;
17221da177e4SLinus Torvalds 	if (sdp->host->cmd_per_lun)
17231da177e4SLinus Torvalds 		scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
17241da177e4SLinus Torvalds 					sdp->host->cmd_per_lun);
1725c65b1445SDouglas Gilbert 	blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
17261da177e4SLinus Torvalds 	return 0;
17271da177e4SLinus Torvalds }
17281da177e4SLinus Torvalds 
17291da177e4SLinus Torvalds static void scsi_debug_slave_destroy(struct scsi_device * sdp)
17301da177e4SLinus Torvalds {
17311da177e4SLinus Torvalds 	struct sdebug_dev_info * devip =
17321da177e4SLinus Torvalds 				(struct sdebug_dev_info *)sdp->hostdata;
17331da177e4SLinus Torvalds 
17341da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1735c65b1445SDouglas Gilbert 		printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
1736c65b1445SDouglas Gilbert 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
17371da177e4SLinus Torvalds 	if (devip) {
17381da177e4SLinus Torvalds 		/* make this slot avaliable for re-use */
17391da177e4SLinus Torvalds 		devip->used = 0;
17401da177e4SLinus Torvalds 		sdp->hostdata = NULL;
17411da177e4SLinus Torvalds 	}
17421da177e4SLinus Torvalds }
17431da177e4SLinus Torvalds 
17445cb2fc06SFUJITA Tomonori struct sdebug_dev_info *sdebug_device_create(struct sdebug_host_info *sdbg_host,
17455cb2fc06SFUJITA Tomonori 					     gfp_t flags)
17465cb2fc06SFUJITA Tomonori {
17475cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
17485cb2fc06SFUJITA Tomonori 
17495cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
17505cb2fc06SFUJITA Tomonori 	if (devip) {
17515cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
17525cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
17535cb2fc06SFUJITA Tomonori 	}
17545cb2fc06SFUJITA Tomonori 	return devip;
17555cb2fc06SFUJITA Tomonori }
17565cb2fc06SFUJITA Tomonori 
17571da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
17581da177e4SLinus Torvalds {
17591da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
17601da177e4SLinus Torvalds 	struct sdebug_dev_info * open_devip = NULL;
17611da177e4SLinus Torvalds 	struct sdebug_dev_info * devip =
17621da177e4SLinus Torvalds 			(struct sdebug_dev_info *)sdev->hostdata;
17631da177e4SLinus Torvalds 
17641da177e4SLinus Torvalds 	if (devip)
17651da177e4SLinus Torvalds 		return devip;
1766d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
17671da177e4SLinus Torvalds 	if (!sdbg_host) {
17681da177e4SLinus Torvalds                 printk(KERN_ERR "Host info NULL\n");
17691da177e4SLinus Torvalds 		return NULL;
17701da177e4SLinus Torvalds         }
17711da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
17721da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
17731da177e4SLinus Torvalds                     (devip->target == sdev->id) &&
17741da177e4SLinus Torvalds                     (devip->lun == sdev->lun))
17751da177e4SLinus Torvalds                         return devip;
17761da177e4SLinus Torvalds 		else {
17771da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
17781da177e4SLinus Torvalds 				open_devip = devip;
17791da177e4SLinus Torvalds 		}
17801da177e4SLinus Torvalds 	}
17815cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
17825cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
17835cb2fc06SFUJITA Tomonori 		if (!open_devip) {
17841da177e4SLinus Torvalds 			printk(KERN_ERR "%s: out of memory at line %d\n",
17851da177e4SLinus Torvalds 				__FUNCTION__, __LINE__);
17861da177e4SLinus Torvalds 			return NULL;
17871da177e4SLinus Torvalds 		}
17881da177e4SLinus Torvalds 	}
1789a75869d1SFUJITA Tomonori 
17901da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
17911da177e4SLinus Torvalds 	open_devip->target = sdev->id;
17921da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
17931da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
17941da177e4SLinus Torvalds 	open_devip->reset = 1;
17951da177e4SLinus Torvalds 	open_devip->used = 1;
17961da177e4SLinus Torvalds 	memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
17971da177e4SLinus Torvalds 	if (scsi_debug_dsense)
17981da177e4SLinus Torvalds 		open_devip->sense_buff[0] = 0x72;
17991da177e4SLinus Torvalds 	else {
18001da177e4SLinus Torvalds 		open_devip->sense_buff[0] = 0x70;
18011da177e4SLinus Torvalds 		open_devip->sense_buff[7] = 0xa;
18021da177e4SLinus Torvalds 	}
1803c65b1445SDouglas Gilbert 	if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
1804c65b1445SDouglas Gilbert 		open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
1805a75869d1SFUJITA Tomonori 
18061da177e4SLinus Torvalds 	return open_devip;
18071da177e4SLinus Torvalds }
18081da177e4SLinus Torvalds 
18091da177e4SLinus Torvalds static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
18101da177e4SLinus Torvalds 			    int asc, int asq)
18111da177e4SLinus Torvalds {
18121da177e4SLinus Torvalds 	unsigned char *sbuff;
18131da177e4SLinus Torvalds 
18141da177e4SLinus Torvalds 	sbuff = devip->sense_buff;
18151da177e4SLinus Torvalds 	memset(sbuff, 0, SDEBUG_SENSE_LEN);
1816a34c4e98SFUJITA Tomonori 
1817a34c4e98SFUJITA Tomonori 	scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
1818a34c4e98SFUJITA Tomonori 
18191da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
18201da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug:    [sense_key,asc,ascq]: "
18211da177e4SLinus Torvalds 		      "[0x%x,0x%x,0x%x]\n", key, asc, asq);
18221da177e4SLinus Torvalds }
18231da177e4SLinus Torvalds 
18241da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
18251da177e4SLinus Torvalds {
18261da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
18271da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: abort\n");
18281da177e4SLinus Torvalds 	++num_aborts;
18291da177e4SLinus Torvalds 	stop_queued_cmnd(SCpnt);
18301da177e4SLinus Torvalds 	return SUCCESS;
18311da177e4SLinus Torvalds }
18321da177e4SLinus Torvalds 
18331da177e4SLinus Torvalds static int scsi_debug_biosparam(struct scsi_device *sdev,
18341da177e4SLinus Torvalds 		struct block_device * bdev, sector_t capacity, int *info)
18351da177e4SLinus Torvalds {
18361da177e4SLinus Torvalds 	int res;
18371da177e4SLinus Torvalds 	unsigned char *buf;
18381da177e4SLinus Torvalds 
18391da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
18401da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: biosparam\n");
18411da177e4SLinus Torvalds 	buf = scsi_bios_ptable(bdev);
18421da177e4SLinus Torvalds 	if (buf) {
18431da177e4SLinus Torvalds 		res = scsi_partsize(buf, capacity,
18441da177e4SLinus Torvalds 				    &info[2], &info[0], &info[1]);
18451da177e4SLinus Torvalds 		kfree(buf);
18461da177e4SLinus Torvalds 		if (! res)
18471da177e4SLinus Torvalds 			return res;
18481da177e4SLinus Torvalds 	}
18491da177e4SLinus Torvalds 	info[0] = sdebug_heads;
18501da177e4SLinus Torvalds 	info[1] = sdebug_sectors_per;
18511da177e4SLinus Torvalds 	info[2] = sdebug_cylinders_per;
18521da177e4SLinus Torvalds 	return 0;
18531da177e4SLinus Torvalds }
18541da177e4SLinus Torvalds 
18551da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
18561da177e4SLinus Torvalds {
18571da177e4SLinus Torvalds 	struct sdebug_dev_info * devip;
18581da177e4SLinus Torvalds 
18591da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
18601da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: device_reset\n");
18611da177e4SLinus Torvalds 	++num_dev_resets;
18621da177e4SLinus Torvalds 	if (SCpnt) {
18631da177e4SLinus Torvalds 		devip = devInfoReg(SCpnt->device);
18641da177e4SLinus Torvalds 		if (devip)
18651da177e4SLinus Torvalds 			devip->reset = 1;
18661da177e4SLinus Torvalds 	}
18671da177e4SLinus Torvalds 	return SUCCESS;
18681da177e4SLinus Torvalds }
18691da177e4SLinus Torvalds 
18701da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
18711da177e4SLinus Torvalds {
18721da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
18731da177e4SLinus Torvalds         struct sdebug_dev_info * dev_info;
18741da177e4SLinus Torvalds         struct scsi_device * sdp;
18751da177e4SLinus Torvalds         struct Scsi_Host * hp;
18761da177e4SLinus Torvalds 
18771da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
18781da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: bus_reset\n");
18791da177e4SLinus Torvalds 	++num_bus_resets;
18801da177e4SLinus Torvalds 	if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
1881d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
18821da177e4SLinus Torvalds 		if (sdbg_host) {
18831da177e4SLinus Torvalds 			list_for_each_entry(dev_info,
18841da177e4SLinus Torvalds                                             &sdbg_host->dev_info_list,
18851da177e4SLinus Torvalds                                             dev_list)
18861da177e4SLinus Torvalds 				dev_info->reset = 1;
18871da177e4SLinus Torvalds 		}
18881da177e4SLinus Torvalds 	}
18891da177e4SLinus Torvalds 	return SUCCESS;
18901da177e4SLinus Torvalds }
18911da177e4SLinus Torvalds 
18921da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
18931da177e4SLinus Torvalds {
18941da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
18951da177e4SLinus Torvalds         struct sdebug_dev_info * dev_info;
18961da177e4SLinus Torvalds 
18971da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
18981da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: host_reset\n");
18991da177e4SLinus Torvalds 	++num_host_resets;
19001da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
19011da177e4SLinus Torvalds         list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
19021da177e4SLinus Torvalds                 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
19031da177e4SLinus Torvalds                                     dev_list)
19041da177e4SLinus Torvalds                         dev_info->reset = 1;
19051da177e4SLinus Torvalds         }
19061da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
19071da177e4SLinus Torvalds 	stop_all_queued();
19081da177e4SLinus Torvalds 	return SUCCESS;
19091da177e4SLinus Torvalds }
19101da177e4SLinus Torvalds 
19111da177e4SLinus Torvalds /* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
19121da177e4SLinus Torvalds static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
19131da177e4SLinus Torvalds {
19141da177e4SLinus Torvalds 	unsigned long iflags;
19151da177e4SLinus Torvalds 	int k;
19161da177e4SLinus Torvalds 	struct sdebug_queued_cmd * sqcp;
19171da177e4SLinus Torvalds 
19181da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
19191da177e4SLinus Torvalds 	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
19201da177e4SLinus Torvalds 		sqcp = &queued_arr[k];
19211da177e4SLinus Torvalds 		if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
19221da177e4SLinus Torvalds 			del_timer_sync(&sqcp->cmnd_timer);
19231da177e4SLinus Torvalds 			sqcp->in_use = 0;
19241da177e4SLinus Torvalds 			sqcp->a_cmnd = NULL;
19251da177e4SLinus Torvalds 			break;
19261da177e4SLinus Torvalds 		}
19271da177e4SLinus Torvalds 	}
19281da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
19291da177e4SLinus Torvalds 	return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
19301da177e4SLinus Torvalds }
19311da177e4SLinus Torvalds 
19321da177e4SLinus Torvalds /* Deletes (stops) timers of all queued commands */
19331da177e4SLinus Torvalds static void stop_all_queued(void)
19341da177e4SLinus Torvalds {
19351da177e4SLinus Torvalds 	unsigned long iflags;
19361da177e4SLinus Torvalds 	int k;
19371da177e4SLinus Torvalds 	struct sdebug_queued_cmd * sqcp;
19381da177e4SLinus Torvalds 
19391da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
19401da177e4SLinus Torvalds 	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
19411da177e4SLinus Torvalds 		sqcp = &queued_arr[k];
19421da177e4SLinus Torvalds 		if (sqcp->in_use && sqcp->a_cmnd) {
19431da177e4SLinus Torvalds 			del_timer_sync(&sqcp->cmnd_timer);
19441da177e4SLinus Torvalds 			sqcp->in_use = 0;
19451da177e4SLinus Torvalds 			sqcp->a_cmnd = NULL;
19461da177e4SLinus Torvalds 		}
19471da177e4SLinus Torvalds 	}
19481da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
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 
19681da177e4SLinus Torvalds static void __init sdebug_build_parts(unsigned char * ramp)
19691da177e4SLinus Torvalds {
19701da177e4SLinus Torvalds 	struct partition * pp;
19711da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
19721da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
19731da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
19741da177e4SLinus Torvalds 
19751da177e4SLinus Torvalds 	/* assume partition table already zeroed */
19761da177e4SLinus Torvalds 	if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576))
19771da177e4SLinus Torvalds 		return;
19781da177e4SLinus Torvalds 	if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
19791da177e4SLinus Torvalds 		scsi_debug_num_parts = SDEBUG_MAX_PARTS;
19801da177e4SLinus Torvalds 		printk(KERN_WARNING "scsi_debug:build_parts: reducing "
19811da177e4SLinus Torvalds 				    "partitions to %d\n", SDEBUG_MAX_PARTS);
19821da177e4SLinus Torvalds 	}
1983c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
19841da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
19851da177e4SLinus Torvalds 			   / scsi_debug_num_parts;
19861da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
19871da177e4SLinus Torvalds         starts[0] = sdebug_sectors_per;
19881da177e4SLinus Torvalds 	for (k = 1; k < scsi_debug_num_parts; ++k)
19891da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
19901da177e4SLinus Torvalds 			    * heads_by_sects;
19911da177e4SLinus Torvalds 	starts[scsi_debug_num_parts] = num_sectors;
19921da177e4SLinus Torvalds 	starts[scsi_debug_num_parts + 1] = 0;
19931da177e4SLinus Torvalds 
19941da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
19951da177e4SLinus Torvalds 	ramp[511] = 0xAA;
19961da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
19971da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
19981da177e4SLinus Torvalds 		start_sec = starts[k];
19991da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
20001da177e4SLinus Torvalds 		pp->boot_ind = 0;
20011da177e4SLinus Torvalds 
20021da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
20031da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
20041da177e4SLinus Torvalds 			   / sdebug_sectors_per;
20051da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
20061da177e4SLinus Torvalds 
20071da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
20081da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
20091da177e4SLinus Torvalds 			       / sdebug_sectors_per;
20101da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
20111da177e4SLinus Torvalds 
20121da177e4SLinus Torvalds 		pp->start_sect = start_sec;
20131da177e4SLinus Torvalds 		pp->nr_sects = end_sec - start_sec + 1;
20141da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
20151da177e4SLinus Torvalds 	}
20161da177e4SLinus Torvalds }
20171da177e4SLinus Torvalds 
20181da177e4SLinus Torvalds static int schedule_resp(struct scsi_cmnd * cmnd,
20191da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip,
20201da177e4SLinus Torvalds 			 done_funct_t done, int scsi_result, int delta_jiff)
20211da177e4SLinus Torvalds {
20221da177e4SLinus Torvalds 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
20231da177e4SLinus Torvalds 		if (scsi_result) {
20241da177e4SLinus Torvalds 			struct scsi_device * sdp = cmnd->device;
20251da177e4SLinus Torvalds 
2026c65b1445SDouglas Gilbert 			printk(KERN_INFO "scsi_debug:    <%u %u %u %u> "
2027c65b1445SDouglas Gilbert 			       "non-zero result=0x%x\n", sdp->host->host_no,
2028c65b1445SDouglas Gilbert 			       sdp->channel, sdp->id, sdp->lun, scsi_result);
20291da177e4SLinus Torvalds 		}
20301da177e4SLinus Torvalds 	}
20311da177e4SLinus Torvalds 	if (cmnd && devip) {
20321da177e4SLinus Torvalds 		/* simulate autosense by this driver */
20331da177e4SLinus Torvalds 		if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
20341da177e4SLinus Torvalds 			memcpy(cmnd->sense_buffer, devip->sense_buff,
20351da177e4SLinus Torvalds 			       (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
20361da177e4SLinus Torvalds 			       SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
20371da177e4SLinus Torvalds 	}
20381da177e4SLinus Torvalds 	if (delta_jiff <= 0) {
20391da177e4SLinus Torvalds 		if (cmnd)
20401da177e4SLinus Torvalds 			cmnd->result = scsi_result;
20411da177e4SLinus Torvalds 		if (done)
20421da177e4SLinus Torvalds 			done(cmnd);
20431da177e4SLinus Torvalds 		return 0;
20441da177e4SLinus Torvalds 	} else {
20451da177e4SLinus Torvalds 		unsigned long iflags;
20461da177e4SLinus Torvalds 		int k;
20471da177e4SLinus Torvalds 		struct sdebug_queued_cmd * sqcp = NULL;
20481da177e4SLinus Torvalds 
20491da177e4SLinus Torvalds 		spin_lock_irqsave(&queued_arr_lock, iflags);
20501da177e4SLinus Torvalds 		for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
20511da177e4SLinus Torvalds 			sqcp = &queued_arr[k];
20521da177e4SLinus Torvalds 			if (! sqcp->in_use)
20531da177e4SLinus Torvalds 				break;
20541da177e4SLinus Torvalds 		}
20551da177e4SLinus Torvalds 		if (k >= SCSI_DEBUG_CANQUEUE) {
20561da177e4SLinus Torvalds 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
20571da177e4SLinus Torvalds 			printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
20581da177e4SLinus Torvalds 			return 1;	/* report busy to mid level */
20591da177e4SLinus Torvalds 		}
20601da177e4SLinus Torvalds 		sqcp->in_use = 1;
20611da177e4SLinus Torvalds 		sqcp->a_cmnd = cmnd;
20621da177e4SLinus Torvalds 		sqcp->scsi_result = scsi_result;
20631da177e4SLinus Torvalds 		sqcp->done_funct = done;
20641da177e4SLinus Torvalds 		sqcp->cmnd_timer.function = timer_intr_handler;
20651da177e4SLinus Torvalds 		sqcp->cmnd_timer.data = k;
20661da177e4SLinus Torvalds 		sqcp->cmnd_timer.expires = jiffies + delta_jiff;
20671da177e4SLinus Torvalds 		add_timer(&sqcp->cmnd_timer);
20681da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
20691da177e4SLinus Torvalds 		if (cmnd)
20701da177e4SLinus Torvalds 			cmnd->result = 0;
20711da177e4SLinus Torvalds 		return 0;
20721da177e4SLinus Torvalds 	}
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);
20971da177e4SLinus Torvalds 
20981da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
20991da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
21001da177e4SLinus Torvalds MODULE_LICENSE("GPL");
21011da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION);
21021da177e4SLinus Torvalds 
21031da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
21041da177e4SLinus Torvalds MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
2105c65b1445SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2106c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
2107beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
210823183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
2109c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2110c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
21111da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
2112c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
21136f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
21141da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
21151da177e4SLinus Torvalds MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
2116c65b1445SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
211723183910SDouglas Gilbert MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
21181da177e4SLinus Torvalds 
21191da177e4SLinus Torvalds 
21201da177e4SLinus Torvalds static char sdebug_info[256];
21211da177e4SLinus Torvalds 
21221da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp)
21231da177e4SLinus Torvalds {
21241da177e4SLinus Torvalds 	sprintf(sdebug_info, "scsi_debug, version %s [%s], "
21251da177e4SLinus Torvalds 		"dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
21261da177e4SLinus Torvalds 		scsi_debug_version_date, scsi_debug_dev_size_mb,
21271da177e4SLinus Torvalds 		scsi_debug_opts);
21281da177e4SLinus Torvalds 	return sdebug_info;
21291da177e4SLinus Torvalds }
21301da177e4SLinus Torvalds 
21311da177e4SLinus Torvalds /* scsi_debug_proc_info
21321da177e4SLinus Torvalds  * Used if the driver currently has no own support for /proc/scsi
21331da177e4SLinus Torvalds  */
21341da177e4SLinus Torvalds static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
21351da177e4SLinus Torvalds 				int length, int inout)
21361da177e4SLinus Torvalds {
21371da177e4SLinus Torvalds 	int len, pos, begin;
21381da177e4SLinus Torvalds 	int orig_length;
21391da177e4SLinus Torvalds 
21401da177e4SLinus Torvalds 	orig_length = length;
21411da177e4SLinus Torvalds 
21421da177e4SLinus Torvalds 	if (inout == 1) {
21431da177e4SLinus Torvalds 		char arr[16];
21441da177e4SLinus Torvalds 		int minLen = length > 15 ? 15 : length;
21451da177e4SLinus Torvalds 
21461da177e4SLinus Torvalds 		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
21471da177e4SLinus Torvalds 			return -EACCES;
21481da177e4SLinus Torvalds 		memcpy(arr, buffer, minLen);
21491da177e4SLinus Torvalds 		arr[minLen] = '\0';
21501da177e4SLinus Torvalds 		if (1 != sscanf(arr, "%d", &pos))
21511da177e4SLinus Torvalds 			return -EINVAL;
21521da177e4SLinus Torvalds 		scsi_debug_opts = pos;
21531da177e4SLinus Torvalds 		if (scsi_debug_every_nth != 0)
21541da177e4SLinus Torvalds                         scsi_debug_cmnd_count = 0;
21551da177e4SLinus Torvalds 		return length;
21561da177e4SLinus Torvalds 	}
21571da177e4SLinus Torvalds 	begin = 0;
21581da177e4SLinus Torvalds 	pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
21591da177e4SLinus Torvalds 	    "%s [%s]\n"
21601da177e4SLinus Torvalds 	    "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
21611da177e4SLinus Torvalds 	    "every_nth=%d(curr:%d)\n"
21621da177e4SLinus Torvalds 	    "delay=%d, max_luns=%d, scsi_level=%d\n"
21631da177e4SLinus Torvalds 	    "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
21641da177e4SLinus Torvalds 	    "number of aborts=%d, device_reset=%d, bus_resets=%d, "
21651da177e4SLinus Torvalds 	    "host_resets=%d\n",
21661da177e4SLinus Torvalds 	    SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
21671da177e4SLinus Torvalds 	    scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
21681da177e4SLinus Torvalds 	    scsi_debug_cmnd_count, scsi_debug_delay,
21691da177e4SLinus Torvalds 	    scsi_debug_max_luns, scsi_debug_scsi_level,
21701da177e4SLinus Torvalds 	    SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
21711da177e4SLinus Torvalds 	    num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
21721da177e4SLinus Torvalds 	if (pos < offset) {
21731da177e4SLinus Torvalds 		len = 0;
21741da177e4SLinus Torvalds 		begin = pos;
21751da177e4SLinus Torvalds 	}
21761da177e4SLinus Torvalds 	*start = buffer + (offset - begin);	/* Start of wanted data */
21771da177e4SLinus Torvalds 	len -= (offset - begin);
21781da177e4SLinus Torvalds 	if (len > length)
21791da177e4SLinus Torvalds 		len = length;
21801da177e4SLinus Torvalds 	return len;
21811da177e4SLinus Torvalds }
21821da177e4SLinus Torvalds 
21831da177e4SLinus Torvalds static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
21841da177e4SLinus Torvalds {
21851da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
21861da177e4SLinus Torvalds }
21871da177e4SLinus Torvalds 
21881da177e4SLinus Torvalds static ssize_t sdebug_delay_store(struct device_driver * ddp,
21891da177e4SLinus Torvalds 				  const char * buf, size_t count)
21901da177e4SLinus Torvalds {
21911da177e4SLinus Torvalds         int delay;
21921da177e4SLinus Torvalds 	char work[20];
21931da177e4SLinus Torvalds 
21941da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
21951da177e4SLinus Torvalds 		if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
21961da177e4SLinus Torvalds 			scsi_debug_delay = delay;
21971da177e4SLinus Torvalds 			return count;
21981da177e4SLinus Torvalds 		}
21991da177e4SLinus Torvalds 	}
22001da177e4SLinus Torvalds 	return -EINVAL;
22011da177e4SLinus Torvalds }
22021da177e4SLinus Torvalds DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
22031da177e4SLinus Torvalds 	    sdebug_delay_store);
22041da177e4SLinus Torvalds 
22051da177e4SLinus Torvalds static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
22061da177e4SLinus Torvalds {
22071da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
22081da177e4SLinus Torvalds }
22091da177e4SLinus Torvalds 
22101da177e4SLinus Torvalds static ssize_t sdebug_opts_store(struct device_driver * ddp,
22111da177e4SLinus Torvalds 				 const char * buf, size_t count)
22121da177e4SLinus Torvalds {
22131da177e4SLinus Torvalds         int opts;
22141da177e4SLinus Torvalds 	char work[20];
22151da177e4SLinus Torvalds 
22161da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
22171da177e4SLinus Torvalds 		if (0 == strnicmp(work,"0x", 2)) {
22181da177e4SLinus Torvalds 			if (1 == sscanf(&work[2], "%x", &opts))
22191da177e4SLinus Torvalds 				goto opts_done;
22201da177e4SLinus Torvalds 		} else {
22211da177e4SLinus Torvalds 			if (1 == sscanf(work, "%d", &opts))
22221da177e4SLinus Torvalds 				goto opts_done;
22231da177e4SLinus Torvalds 		}
22241da177e4SLinus Torvalds 	}
22251da177e4SLinus Torvalds 	return -EINVAL;
22261da177e4SLinus Torvalds opts_done:
22271da177e4SLinus Torvalds 	scsi_debug_opts = opts;
22281da177e4SLinus Torvalds 	scsi_debug_cmnd_count = 0;
22291da177e4SLinus Torvalds 	return count;
22301da177e4SLinus Torvalds }
22311da177e4SLinus Torvalds DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
22321da177e4SLinus Torvalds 	    sdebug_opts_store);
22331da177e4SLinus Torvalds 
22341da177e4SLinus Torvalds static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
22351da177e4SLinus Torvalds {
22361da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
22371da177e4SLinus Torvalds }
22381da177e4SLinus Torvalds static ssize_t sdebug_ptype_store(struct device_driver * ddp,
22391da177e4SLinus Torvalds 				  const char * buf, size_t count)
22401da177e4SLinus Torvalds {
22411da177e4SLinus Torvalds         int n;
22421da177e4SLinus Torvalds 
22431da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
22441da177e4SLinus Torvalds 		scsi_debug_ptype = n;
22451da177e4SLinus Torvalds 		return count;
22461da177e4SLinus Torvalds 	}
22471da177e4SLinus Torvalds 	return -EINVAL;
22481da177e4SLinus Torvalds }
22491da177e4SLinus Torvalds DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
22501da177e4SLinus Torvalds 
22511da177e4SLinus Torvalds static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
22521da177e4SLinus Torvalds {
22531da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
22541da177e4SLinus Torvalds }
22551da177e4SLinus Torvalds static ssize_t sdebug_dsense_store(struct device_driver * ddp,
22561da177e4SLinus Torvalds 				  const char * buf, size_t count)
22571da177e4SLinus Torvalds {
22581da177e4SLinus Torvalds         int n;
22591da177e4SLinus Torvalds 
22601da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
22611da177e4SLinus Torvalds 		scsi_debug_dsense = n;
22621da177e4SLinus Torvalds 		return count;
22631da177e4SLinus Torvalds 	}
22641da177e4SLinus Torvalds 	return -EINVAL;
22651da177e4SLinus Torvalds }
22661da177e4SLinus Torvalds DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
22671da177e4SLinus Torvalds 	    sdebug_dsense_store);
22681da177e4SLinus Torvalds 
226923183910SDouglas Gilbert static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
227023183910SDouglas Gilbert {
227123183910SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
227223183910SDouglas Gilbert }
227323183910SDouglas Gilbert static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
227423183910SDouglas Gilbert 				    const char * buf, size_t count)
227523183910SDouglas Gilbert {
227623183910SDouglas Gilbert         int n;
227723183910SDouglas Gilbert 
227823183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
227923183910SDouglas Gilbert 		scsi_debug_fake_rw = n;
228023183910SDouglas Gilbert 		return count;
228123183910SDouglas Gilbert 	}
228223183910SDouglas Gilbert 	return -EINVAL;
228323183910SDouglas Gilbert }
228423183910SDouglas Gilbert DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
228523183910SDouglas Gilbert 	    sdebug_fake_rw_store);
228623183910SDouglas Gilbert 
2287c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2288c65b1445SDouglas Gilbert {
2289c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2290c65b1445SDouglas Gilbert }
2291c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2292c65b1445SDouglas Gilbert 				     const char * buf, size_t count)
2293c65b1445SDouglas Gilbert {
2294c65b1445SDouglas Gilbert         int n;
2295c65b1445SDouglas Gilbert 
2296c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2297c65b1445SDouglas Gilbert 		scsi_debug_no_lun_0 = n;
2298c65b1445SDouglas Gilbert 		return count;
2299c65b1445SDouglas Gilbert 	}
2300c65b1445SDouglas Gilbert 	return -EINVAL;
2301c65b1445SDouglas Gilbert }
2302c65b1445SDouglas Gilbert DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2303c65b1445SDouglas Gilbert 	    sdebug_no_lun_0_store);
2304c65b1445SDouglas Gilbert 
23051da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
23061da177e4SLinus Torvalds {
23071da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
23081da177e4SLinus Torvalds }
23091da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
23101da177e4SLinus Torvalds 				     const char * buf, size_t count)
23111da177e4SLinus Torvalds {
23121da177e4SLinus Torvalds         int n;
23131da177e4SLinus Torvalds 
23141da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
23151da177e4SLinus Torvalds 		scsi_debug_num_tgts = n;
23161da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
23171da177e4SLinus Torvalds 		return count;
23181da177e4SLinus Torvalds 	}
23191da177e4SLinus Torvalds 	return -EINVAL;
23201da177e4SLinus Torvalds }
23211da177e4SLinus Torvalds DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
23221da177e4SLinus Torvalds 	    sdebug_num_tgts_store);
23231da177e4SLinus Torvalds 
23241da177e4SLinus Torvalds static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
23251da177e4SLinus Torvalds {
23261da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
23271da177e4SLinus Torvalds }
23281da177e4SLinus Torvalds DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
23291da177e4SLinus Torvalds 
23301da177e4SLinus Torvalds static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
23311da177e4SLinus Torvalds {
23321da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
23331da177e4SLinus Torvalds }
23341da177e4SLinus Torvalds DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
23351da177e4SLinus Torvalds 
23361da177e4SLinus Torvalds static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
23371da177e4SLinus Torvalds {
23381da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
23391da177e4SLinus Torvalds }
23401da177e4SLinus Torvalds static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
23411da177e4SLinus Torvalds 				      const char * buf, size_t count)
23421da177e4SLinus Torvalds {
23431da177e4SLinus Torvalds         int nth;
23441da177e4SLinus Torvalds 
23451da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
23461da177e4SLinus Torvalds 		scsi_debug_every_nth = nth;
23471da177e4SLinus Torvalds 		scsi_debug_cmnd_count = 0;
23481da177e4SLinus Torvalds 		return count;
23491da177e4SLinus Torvalds 	}
23501da177e4SLinus Torvalds 	return -EINVAL;
23511da177e4SLinus Torvalds }
23521da177e4SLinus Torvalds DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
23531da177e4SLinus Torvalds 	    sdebug_every_nth_store);
23541da177e4SLinus Torvalds 
23551da177e4SLinus Torvalds static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
23561da177e4SLinus Torvalds {
23571da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
23581da177e4SLinus Torvalds }
23591da177e4SLinus Torvalds static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
23601da177e4SLinus Torvalds 				     const char * buf, size_t count)
23611da177e4SLinus Torvalds {
23621da177e4SLinus Torvalds         int n;
23631da177e4SLinus Torvalds 
23641da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
23651da177e4SLinus Torvalds 		scsi_debug_max_luns = n;
23661da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
23671da177e4SLinus Torvalds 		return count;
23681da177e4SLinus Torvalds 	}
23691da177e4SLinus Torvalds 	return -EINVAL;
23701da177e4SLinus Torvalds }
23711da177e4SLinus Torvalds DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
23721da177e4SLinus Torvalds 	    sdebug_max_luns_store);
23731da177e4SLinus Torvalds 
23741da177e4SLinus Torvalds static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
23751da177e4SLinus Torvalds {
23761da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
23771da177e4SLinus Torvalds }
23781da177e4SLinus Torvalds DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
23791da177e4SLinus Torvalds 
2380c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2381c65b1445SDouglas Gilbert {
2382c65b1445SDouglas Gilbert         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2383c65b1445SDouglas Gilbert }
2384c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2385c65b1445SDouglas Gilbert 				       const char * buf, size_t count)
2386c65b1445SDouglas Gilbert {
2387c65b1445SDouglas Gilbert         int n;
2388c65b1445SDouglas Gilbert 
2389c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2390c65b1445SDouglas Gilbert 		scsi_debug_virtual_gb = n;
2391c65b1445SDouglas Gilbert 		if (scsi_debug_virtual_gb > 0) {
2392c65b1445SDouglas Gilbert 			sdebug_capacity = 2048 * 1024;
2393c65b1445SDouglas Gilbert 			sdebug_capacity *= scsi_debug_virtual_gb;
2394c65b1445SDouglas Gilbert 		} else
2395c65b1445SDouglas Gilbert 			sdebug_capacity = sdebug_store_sectors;
2396c65b1445SDouglas Gilbert 		return count;
2397c65b1445SDouglas Gilbert 	}
2398c65b1445SDouglas Gilbert 	return -EINVAL;
2399c65b1445SDouglas Gilbert }
2400c65b1445SDouglas Gilbert DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2401c65b1445SDouglas Gilbert 	    sdebug_virtual_gb_store);
2402c65b1445SDouglas Gilbert 
24031da177e4SLinus Torvalds static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
24041da177e4SLinus Torvalds {
24051da177e4SLinus Torvalds         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
24061da177e4SLinus Torvalds }
24071da177e4SLinus Torvalds 
24081da177e4SLinus Torvalds static ssize_t sdebug_add_host_store(struct device_driver * ddp,
24091da177e4SLinus Torvalds 				     const char * buf, size_t count)
24101da177e4SLinus Torvalds {
24111da177e4SLinus Torvalds 	int delta_hosts;
24121da177e4SLinus Torvalds 
2413f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
24141da177e4SLinus Torvalds 		return -EINVAL;
24151da177e4SLinus Torvalds 	if (delta_hosts > 0) {
24161da177e4SLinus Torvalds 		do {
24171da177e4SLinus Torvalds 			sdebug_add_adapter();
24181da177e4SLinus Torvalds 		} while (--delta_hosts);
24191da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
24201da177e4SLinus Torvalds 		do {
24211da177e4SLinus Torvalds 			sdebug_remove_adapter();
24221da177e4SLinus Torvalds 		} while (++delta_hosts);
24231da177e4SLinus Torvalds 	}
24241da177e4SLinus Torvalds 	return count;
24251da177e4SLinus Torvalds }
24261da177e4SLinus Torvalds DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
24271da177e4SLinus Torvalds 	    sdebug_add_host_store);
24281da177e4SLinus Torvalds 
242923183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
243023183910SDouglas Gilbert 					  char * buf)
243123183910SDouglas Gilbert {
243223183910SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
243323183910SDouglas Gilbert }
243423183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
243523183910SDouglas Gilbert 					   const char * buf, size_t count)
243623183910SDouglas Gilbert {
243723183910SDouglas Gilbert 	int n;
243823183910SDouglas Gilbert 
243923183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
244023183910SDouglas Gilbert 		scsi_debug_vpd_use_hostno = n;
244123183910SDouglas Gilbert 		return count;
244223183910SDouglas Gilbert 	}
244323183910SDouglas Gilbert 	return -EINVAL;
244423183910SDouglas Gilbert }
244523183910SDouglas Gilbert DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
244623183910SDouglas Gilbert 	    sdebug_vpd_use_hostno_store);
244723183910SDouglas Gilbert 
244823183910SDouglas Gilbert /* Note: The following function creates attribute files in the
244923183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
245023183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
245123183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
245223183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
245323183910SDouglas Gilbert  */
24546ecaff7fSRandy Dunlap static int do_create_driverfs_files(void)
24551da177e4SLinus Torvalds {
24566ecaff7fSRandy Dunlap 	int ret;
24576ecaff7fSRandy Dunlap 
24586ecaff7fSRandy Dunlap 	ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
24596ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
24606ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
24616ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
24626ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
246323183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
24646ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
246523183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
24666ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
246723183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
24686ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
24696ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
24706ecaff7fSRandy Dunlap 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
247123183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
247223183910SDouglas Gilbert 	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
24736ecaff7fSRandy Dunlap 	return ret;
24741da177e4SLinus Torvalds }
24751da177e4SLinus Torvalds 
24761da177e4SLinus Torvalds static void do_remove_driverfs_files(void)
24771da177e4SLinus Torvalds {
247823183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
247923183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
24801da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
24811da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
24821da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
24831da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
248423183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
248523183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
24861da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
248723183910SDouglas Gilbert 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
24881da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
24891da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
24901da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
24911da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
24921da177e4SLinus Torvalds 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
24931da177e4SLinus Torvalds }
24941da177e4SLinus Torvalds 
24951da177e4SLinus Torvalds static int __init scsi_debug_init(void)
24961da177e4SLinus Torvalds {
2497c65b1445SDouglas Gilbert 	unsigned int sz;
24981da177e4SLinus Torvalds 	int host_to_add;
24991da177e4SLinus Torvalds 	int k;
25006ecaff7fSRandy Dunlap 	int ret;
25011da177e4SLinus Torvalds 
25021da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb < 1)
25031da177e4SLinus Torvalds 		scsi_debug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
2504c65b1445SDouglas Gilbert 	sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576;
2505c65b1445SDouglas Gilbert 	sdebug_store_sectors = sdebug_store_size / SECT_SIZE;
2506c65b1445SDouglas Gilbert 	if (scsi_debug_virtual_gb > 0) {
2507c65b1445SDouglas Gilbert 		sdebug_capacity = 2048 * 1024;
2508c65b1445SDouglas Gilbert 		sdebug_capacity *= scsi_debug_virtual_gb;
2509c65b1445SDouglas Gilbert 	} else
2510c65b1445SDouglas Gilbert 		sdebug_capacity = sdebug_store_sectors;
25111da177e4SLinus Torvalds 
25121da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
25131da177e4SLinus Torvalds 	sdebug_heads = 8;
25141da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
25151da177e4SLinus Torvalds 	if (scsi_debug_dev_size_mb >= 16)
25161da177e4SLinus Torvalds 		sdebug_heads = 32;
25171da177e4SLinus Torvalds 	else if (scsi_debug_dev_size_mb >= 256)
25181da177e4SLinus Torvalds 		sdebug_heads = 64;
25191da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
25201da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
25211da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
25221da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
25231da177e4SLinus Torvalds 		sdebug_heads = 255;
25241da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
25251da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
25261da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
25271da177e4SLinus Torvalds 	}
25281da177e4SLinus Torvalds 
25291da177e4SLinus Torvalds 	sz = sdebug_store_size;
25301da177e4SLinus Torvalds 	fake_storep = vmalloc(sz);
25311da177e4SLinus Torvalds 	if (NULL == fake_storep) {
25321da177e4SLinus Torvalds 		printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
25331da177e4SLinus Torvalds 		return -ENOMEM;
25341da177e4SLinus Torvalds 	}
25351da177e4SLinus Torvalds 	memset(fake_storep, 0, sz);
25361da177e4SLinus Torvalds 	if (scsi_debug_num_parts > 0)
25371da177e4SLinus Torvalds 		sdebug_build_parts(fake_storep);
25381da177e4SLinus Torvalds 
25396ecaff7fSRandy Dunlap 	ret = device_register(&pseudo_primary);
25406ecaff7fSRandy Dunlap 	if (ret < 0) {
25416ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
25426ecaff7fSRandy Dunlap 			ret);
25436ecaff7fSRandy Dunlap 		goto free_vm;
25446ecaff7fSRandy Dunlap 	}
25456ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
25466ecaff7fSRandy Dunlap 	if (ret < 0) {
25476ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
25486ecaff7fSRandy Dunlap 			ret);
25496ecaff7fSRandy Dunlap 		goto dev_unreg;
25506ecaff7fSRandy Dunlap 	}
25516ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
25526ecaff7fSRandy Dunlap 	if (ret < 0) {
25536ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
25546ecaff7fSRandy Dunlap 			ret);
25556ecaff7fSRandy Dunlap 		goto bus_unreg;
25566ecaff7fSRandy Dunlap 	}
25576ecaff7fSRandy Dunlap 	ret = do_create_driverfs_files();
25586ecaff7fSRandy Dunlap 	if (ret < 0) {
25596ecaff7fSRandy Dunlap 		printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
25606ecaff7fSRandy Dunlap 			ret);
25616ecaff7fSRandy Dunlap 		goto del_files;
25626ecaff7fSRandy Dunlap 	}
25631da177e4SLinus Torvalds 
25646ecaff7fSRandy Dunlap 	init_all_queued();
25651da177e4SLinus Torvalds 
25661da177e4SLinus Torvalds 	host_to_add = scsi_debug_add_host;
25671da177e4SLinus Torvalds         scsi_debug_add_host = 0;
25681da177e4SLinus Torvalds 
25691da177e4SLinus Torvalds         for (k = 0; k < host_to_add; k++) {
25701da177e4SLinus Torvalds                 if (sdebug_add_adapter()) {
25711da177e4SLinus Torvalds                         printk(KERN_ERR "scsi_debug_init: "
25721da177e4SLinus Torvalds                                "sdebug_add_adapter failed k=%d\n", k);
25731da177e4SLinus Torvalds                         break;
25741da177e4SLinus Torvalds                 }
25751da177e4SLinus Torvalds         }
25761da177e4SLinus Torvalds 
25771da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
25781da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
25791da177e4SLinus Torvalds 		       scsi_debug_add_host);
25801da177e4SLinus Torvalds 	}
25811da177e4SLinus Torvalds 	return 0;
25826ecaff7fSRandy Dunlap 
25836ecaff7fSRandy Dunlap del_files:
25846ecaff7fSRandy Dunlap 	do_remove_driverfs_files();
25856ecaff7fSRandy Dunlap 	driver_unregister(&sdebug_driverfs_driver);
25866ecaff7fSRandy Dunlap bus_unreg:
25876ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
25886ecaff7fSRandy Dunlap dev_unreg:
25896ecaff7fSRandy Dunlap 	device_unregister(&pseudo_primary);
25906ecaff7fSRandy Dunlap free_vm:
25916ecaff7fSRandy Dunlap 	vfree(fake_storep);
25926ecaff7fSRandy Dunlap 
25936ecaff7fSRandy Dunlap 	return ret;
25941da177e4SLinus Torvalds }
25951da177e4SLinus Torvalds 
25961da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
25971da177e4SLinus Torvalds {
25981da177e4SLinus Torvalds 	int k = scsi_debug_add_host;
25991da177e4SLinus Torvalds 
26001da177e4SLinus Torvalds 	stop_all_queued();
26011da177e4SLinus Torvalds 	for (; k; k--)
26021da177e4SLinus Torvalds 		sdebug_remove_adapter();
26031da177e4SLinus Torvalds 	do_remove_driverfs_files();
26041da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
26051da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
26061da177e4SLinus Torvalds 	device_unregister(&pseudo_primary);
26071da177e4SLinus Torvalds 
26081da177e4SLinus Torvalds 	vfree(fake_storep);
26091da177e4SLinus Torvalds }
26101da177e4SLinus Torvalds 
26111da177e4SLinus Torvalds device_initcall(scsi_debug_init);
26121da177e4SLinus Torvalds module_exit(scsi_debug_exit);
26131da177e4SLinus Torvalds 
261452c1da39SAdrian Bunk static void pseudo_0_release(struct device * dev)
26151da177e4SLinus Torvalds {
26161da177e4SLinus Torvalds 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
26171da177e4SLinus Torvalds 		printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
26181da177e4SLinus Torvalds }
26191da177e4SLinus Torvalds 
26201da177e4SLinus Torvalds static struct device pseudo_primary = {
26211da177e4SLinus Torvalds 	.bus_id		= "pseudo_0",
26221da177e4SLinus Torvalds 	.release	= pseudo_0_release,
26231da177e4SLinus Torvalds };
26241da177e4SLinus Torvalds 
26251da177e4SLinus Torvalds static int pseudo_lld_bus_match(struct device *dev,
26261da177e4SLinus Torvalds                           struct device_driver *dev_driver)
26271da177e4SLinus Torvalds {
26281da177e4SLinus Torvalds         return 1;
26291da177e4SLinus Torvalds }
26301da177e4SLinus Torvalds 
26311da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus = {
26321da177e4SLinus Torvalds         .name = "pseudo",
26331da177e4SLinus Torvalds         .match = pseudo_lld_bus_match,
2634bbbe3a41SRussell King 	.probe = sdebug_driver_probe,
2635bbbe3a41SRussell King 	.remove = sdebug_driver_remove,
26361da177e4SLinus Torvalds };
26371da177e4SLinus Torvalds 
26381da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev)
26391da177e4SLinus Torvalds {
26401da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
26411da177e4SLinus Torvalds 
26421da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
26431da177e4SLinus Torvalds         kfree(sdbg_host);
26441da177e4SLinus Torvalds }
26451da177e4SLinus Torvalds 
26461da177e4SLinus Torvalds static int sdebug_add_adapter(void)
26471da177e4SLinus Torvalds {
26481da177e4SLinus Torvalds 	int k, devs_per_host;
26491da177e4SLinus Torvalds         int error = 0;
26501da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
26518b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
26521da177e4SLinus Torvalds 
265324669f75SJes Sorensen         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
26541da177e4SLinus Torvalds         if (NULL == sdbg_host) {
26551da177e4SLinus Torvalds                 printk(KERN_ERR "%s: out of memory at line %d\n",
26561da177e4SLinus Torvalds                        __FUNCTION__, __LINE__);
26571da177e4SLinus Torvalds                 return -ENOMEM;
26581da177e4SLinus Torvalds         }
26591da177e4SLinus Torvalds 
26601da177e4SLinus Torvalds         INIT_LIST_HEAD(&sdbg_host->dev_info_list);
26611da177e4SLinus Torvalds 
26621da177e4SLinus Torvalds 	devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
26631da177e4SLinus Torvalds         for (k = 0; k < devs_per_host; k++) {
26645cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
26655cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
26661da177e4SLinus Torvalds                         printk(KERN_ERR "%s: out of memory at line %d\n",
26671da177e4SLinus Torvalds                                __FUNCTION__, __LINE__);
26681da177e4SLinus Torvalds                         error = -ENOMEM;
26691da177e4SLinus Torvalds 			goto clean;
26701da177e4SLinus Torvalds                 }
26711da177e4SLinus Torvalds         }
26721da177e4SLinus Torvalds 
26731da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
26741da177e4SLinus Torvalds         list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
26751da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
26761da177e4SLinus Torvalds 
26771da177e4SLinus Torvalds         sdbg_host->dev.bus = &pseudo_lld_bus;
26781da177e4SLinus Torvalds         sdbg_host->dev.parent = &pseudo_primary;
26791da177e4SLinus Torvalds         sdbg_host->dev.release = &sdebug_release_adapter;
26801da177e4SLinus Torvalds         sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
26811da177e4SLinus Torvalds 
26821da177e4SLinus Torvalds         error = device_register(&sdbg_host->dev);
26831da177e4SLinus Torvalds 
26841da177e4SLinus Torvalds         if (error)
26851da177e4SLinus Torvalds 		goto clean;
26861da177e4SLinus Torvalds 
26871da177e4SLinus Torvalds 	++scsi_debug_add_host;
26881da177e4SLinus Torvalds         return error;
26891da177e4SLinus Torvalds 
26901da177e4SLinus Torvalds clean:
26918b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
26928b40228fSFUJITA Tomonori 				 dev_list) {
26931da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
26941da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
26951da177e4SLinus Torvalds 	}
26961da177e4SLinus Torvalds 
26971da177e4SLinus Torvalds 	kfree(sdbg_host);
26981da177e4SLinus Torvalds         return error;
26991da177e4SLinus Torvalds }
27001da177e4SLinus Torvalds 
27011da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
27021da177e4SLinus Torvalds {
27031da177e4SLinus Torvalds         struct sdebug_host_info * sdbg_host = NULL;
27041da177e4SLinus Torvalds 
27051da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
27061da177e4SLinus Torvalds         if (!list_empty(&sdebug_host_list)) {
27071da177e4SLinus Torvalds                 sdbg_host = list_entry(sdebug_host_list.prev,
27081da177e4SLinus Torvalds                                        struct sdebug_host_info, host_list);
27091da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
27101da177e4SLinus Torvalds 	}
27111da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
27121da177e4SLinus Torvalds 
27131da177e4SLinus Torvalds 	if (!sdbg_host)
27141da177e4SLinus Torvalds 		return;
27151da177e4SLinus Torvalds 
27161da177e4SLinus Torvalds         device_unregister(&sdbg_host->dev);
27171da177e4SLinus Torvalds         --scsi_debug_add_host;
27181da177e4SLinus Torvalds }
27191da177e4SLinus Torvalds 
2720639db475SFUJITA Tomonori static
2721639db475SFUJITA Tomonori int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
2722639db475SFUJITA Tomonori {
2723639db475SFUJITA Tomonori 	unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
2724639db475SFUJITA Tomonori 	int len, k;
2725639db475SFUJITA Tomonori 	unsigned int num;
2726639db475SFUJITA Tomonori 	unsigned long long lba;
2727639db475SFUJITA Tomonori 	int errsts = 0;
2728639db475SFUJITA Tomonori 	int target = SCpnt->device->id;
2729639db475SFUJITA Tomonori 	struct sdebug_dev_info *devip = NULL;
2730639db475SFUJITA Tomonori 	int inj_recovered = 0;
2731639db475SFUJITA Tomonori 	int inj_transport = 0;
2732639db475SFUJITA Tomonori 	int delay_override = 0;
2733639db475SFUJITA Tomonori 
2734639db475SFUJITA Tomonori 	scsi_set_resid(SCpnt, 0);
2735639db475SFUJITA Tomonori 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
2736639db475SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: cmd ");
2737639db475SFUJITA Tomonori 		for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
2738639db475SFUJITA Tomonori 			printk("%02x ", (int)cmd[k]);
2739639db475SFUJITA Tomonori 		printk("\n");
2740639db475SFUJITA Tomonori 	}
2741639db475SFUJITA Tomonori 
2742639db475SFUJITA Tomonori 	if (target == SCpnt->device->host->hostt->this_id) {
2743639db475SFUJITA Tomonori 		printk(KERN_INFO "scsi_debug: initiator's id used as "
2744639db475SFUJITA Tomonori 		       "target!\n");
2745639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
2746639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
2747639db475SFUJITA Tomonori 	}
2748639db475SFUJITA Tomonori 
2749639db475SFUJITA Tomonori 	if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
2750639db475SFUJITA Tomonori 	    (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
2751639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
2752639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
2753639db475SFUJITA Tomonori 	devip = devInfoReg(SCpnt->device);
2754639db475SFUJITA Tomonori 	if (NULL == devip)
2755639db475SFUJITA Tomonori 		return schedule_resp(SCpnt, NULL, done,
2756639db475SFUJITA Tomonori 				     DID_NO_CONNECT << 16, 0);
2757639db475SFUJITA Tomonori 
2758639db475SFUJITA Tomonori 	if ((scsi_debug_every_nth != 0) &&
2759639db475SFUJITA Tomonori 	    (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
2760639db475SFUJITA Tomonori 		scsi_debug_cmnd_count = 0;
2761639db475SFUJITA Tomonori 		if (scsi_debug_every_nth < -1)
2762639db475SFUJITA Tomonori 			scsi_debug_every_nth = -1;
2763639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
2764639db475SFUJITA Tomonori 			return 0; /* ignore command causing timeout */
2765639db475SFUJITA Tomonori 		else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
2766639db475SFUJITA Tomonori 			inj_recovered = 1; /* to reads and writes below */
2767639db475SFUJITA Tomonori 		else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
2768639db475SFUJITA Tomonori 			inj_transport = 1; /* to reads and writes below */
2769639db475SFUJITA Tomonori 	}
2770639db475SFUJITA Tomonori 
2771639db475SFUJITA Tomonori 	if (devip->wlun) {
2772639db475SFUJITA Tomonori 		switch (*cmd) {
2773639db475SFUJITA Tomonori 		case INQUIRY:
2774639db475SFUJITA Tomonori 		case REQUEST_SENSE:
2775639db475SFUJITA Tomonori 		case TEST_UNIT_READY:
2776639db475SFUJITA Tomonori 		case REPORT_LUNS:
2777639db475SFUJITA Tomonori 			break;  /* only allowable wlun commands */
2778639db475SFUJITA Tomonori 		default:
2779639db475SFUJITA Tomonori 			if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2780639db475SFUJITA Tomonori 				printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
2781639db475SFUJITA Tomonori 				       "not supported for wlun\n", *cmd);
2782639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
2783639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
2784639db475SFUJITA Tomonori 			errsts = check_condition_result;
2785639db475SFUJITA Tomonori 			return schedule_resp(SCpnt, devip, done, errsts,
2786639db475SFUJITA Tomonori 					     0);
2787639db475SFUJITA Tomonori 		}
2788639db475SFUJITA Tomonori 	}
2789639db475SFUJITA Tomonori 
2790639db475SFUJITA Tomonori 	switch (*cmd) {
2791639db475SFUJITA Tomonori 	case INQUIRY:     /* mandatory, ignore unit attention */
2792639db475SFUJITA Tomonori 		delay_override = 1;
2793639db475SFUJITA Tomonori 		errsts = resp_inquiry(SCpnt, target, devip);
2794639db475SFUJITA Tomonori 		break;
2795639db475SFUJITA Tomonori 	case REQUEST_SENSE:	/* mandatory, ignore unit attention */
2796639db475SFUJITA Tomonori 		delay_override = 1;
2797639db475SFUJITA Tomonori 		errsts = resp_requests(SCpnt, devip);
2798639db475SFUJITA Tomonori 		break;
2799639db475SFUJITA Tomonori 	case REZERO_UNIT:	/* actually this is REWIND for SSC */
2800639db475SFUJITA Tomonori 	case START_STOP:
2801639db475SFUJITA Tomonori 		errsts = resp_start_stop(SCpnt, devip);
2802639db475SFUJITA Tomonori 		break;
2803639db475SFUJITA Tomonori 	case ALLOW_MEDIUM_REMOVAL:
2804639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2805639db475SFUJITA Tomonori 		if (errsts)
2806639db475SFUJITA Tomonori 			break;
2807639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2808639db475SFUJITA Tomonori 			printk(KERN_INFO "scsi_debug: Medium removal %s\n",
2809639db475SFUJITA Tomonori 			       cmd[4] ? "inhibited" : "enabled");
2810639db475SFUJITA Tomonori 		break;
2811639db475SFUJITA Tomonori 	case SEND_DIAGNOSTIC:     /* mandatory */
2812639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2813639db475SFUJITA Tomonori 		break;
2814639db475SFUJITA Tomonori 	case TEST_UNIT_READY:     /* mandatory */
2815639db475SFUJITA Tomonori 		delay_override = 1;
2816639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
2817639db475SFUJITA Tomonori 		break;
2818639db475SFUJITA Tomonori 	case RESERVE:
2819639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2820639db475SFUJITA Tomonori 		break;
2821639db475SFUJITA Tomonori 	case RESERVE_10:
2822639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2823639db475SFUJITA Tomonori 		break;
2824639db475SFUJITA Tomonori 	case RELEASE:
2825639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2826639db475SFUJITA Tomonori 		break;
2827639db475SFUJITA Tomonori 	case RELEASE_10:
2828639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2829639db475SFUJITA Tomonori 		break;
2830639db475SFUJITA Tomonori 	case READ_CAPACITY:
2831639db475SFUJITA Tomonori 		errsts = resp_readcap(SCpnt, devip);
2832639db475SFUJITA Tomonori 		break;
2833639db475SFUJITA Tomonori 	case SERVICE_ACTION_IN:
2834639db475SFUJITA Tomonori 		if (SAI_READ_CAPACITY_16 != cmd[1]) {
2835639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
2836639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
2837639db475SFUJITA Tomonori 			errsts = check_condition_result;
2838639db475SFUJITA Tomonori 			break;
2839639db475SFUJITA Tomonori 		}
2840639db475SFUJITA Tomonori 		errsts = resp_readcap16(SCpnt, devip);
2841639db475SFUJITA Tomonori 		break;
2842639db475SFUJITA Tomonori 	case MAINTENANCE_IN:
2843639db475SFUJITA Tomonori 		if (MI_REPORT_TARGET_PGS != cmd[1]) {
2844639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
2845639db475SFUJITA Tomonori 					INVALID_OPCODE, 0);
2846639db475SFUJITA Tomonori 			errsts = check_condition_result;
2847639db475SFUJITA Tomonori 			break;
2848639db475SFUJITA Tomonori 		}
2849639db475SFUJITA Tomonori 		errsts = resp_report_tgtpgs(SCpnt, devip);
2850639db475SFUJITA Tomonori 		break;
2851639db475SFUJITA Tomonori 	case READ_16:
2852639db475SFUJITA Tomonori 	case READ_12:
2853639db475SFUJITA Tomonori 	case READ_10:
2854639db475SFUJITA Tomonori 	case READ_6:
2855639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
2856639db475SFUJITA Tomonori 		if (errsts)
2857639db475SFUJITA Tomonori 			break;
2858639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
2859639db475SFUJITA Tomonori 			break;
2860639db475SFUJITA Tomonori 		get_data_transfer_info(cmd, &lba, &num);
2861639db475SFUJITA Tomonori 		errsts = resp_read(SCpnt, lba, num, devip);
2862639db475SFUJITA Tomonori 		if (inj_recovered && (0 == errsts)) {
2863639db475SFUJITA Tomonori 			mk_sense_buffer(devip, RECOVERED_ERROR,
2864639db475SFUJITA Tomonori 					THRESHOLD_EXCEEDED, 0);
2865639db475SFUJITA Tomonori 			errsts = check_condition_result;
2866639db475SFUJITA Tomonori 		} else if (inj_transport && (0 == errsts)) {
2867639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ABORTED_COMMAND,
2868639db475SFUJITA Tomonori 					TRANSPORT_PROBLEM, ACK_NAK_TO);
2869639db475SFUJITA Tomonori 			errsts = check_condition_result;
2870639db475SFUJITA Tomonori 		}
2871639db475SFUJITA Tomonori 		break;
2872639db475SFUJITA Tomonori 	case REPORT_LUNS:	/* mandatory, ignore unit attention */
2873639db475SFUJITA Tomonori 		delay_override = 1;
2874639db475SFUJITA Tomonori 		errsts = resp_report_luns(SCpnt, devip);
2875639db475SFUJITA Tomonori 		break;
2876639db475SFUJITA Tomonori 	case VERIFY:		/* 10 byte SBC-2 command */
2877639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
2878639db475SFUJITA Tomonori 		break;
2879639db475SFUJITA Tomonori 	case WRITE_16:
2880639db475SFUJITA Tomonori 	case WRITE_12:
2881639db475SFUJITA Tomonori 	case WRITE_10:
2882639db475SFUJITA Tomonori 	case WRITE_6:
2883639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
2884639db475SFUJITA Tomonori 		if (errsts)
2885639db475SFUJITA Tomonori 			break;
2886639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
2887639db475SFUJITA Tomonori 			break;
2888639db475SFUJITA Tomonori 		get_data_transfer_info(cmd, &lba, &num);
2889639db475SFUJITA Tomonori 		errsts = resp_write(SCpnt, lba, num, devip);
2890639db475SFUJITA Tomonori 		if (inj_recovered && (0 == errsts)) {
2891639db475SFUJITA Tomonori 			mk_sense_buffer(devip, RECOVERED_ERROR,
2892639db475SFUJITA Tomonori 					THRESHOLD_EXCEEDED, 0);
2893639db475SFUJITA Tomonori 			errsts = check_condition_result;
2894639db475SFUJITA Tomonori 		}
2895639db475SFUJITA Tomonori 		break;
2896639db475SFUJITA Tomonori 	case MODE_SENSE:
2897639db475SFUJITA Tomonori 	case MODE_SENSE_10:
2898639db475SFUJITA Tomonori 		errsts = resp_mode_sense(SCpnt, target, devip);
2899639db475SFUJITA Tomonori 		break;
2900639db475SFUJITA Tomonori 	case MODE_SELECT:
2901639db475SFUJITA Tomonori 		errsts = resp_mode_select(SCpnt, 1, devip);
2902639db475SFUJITA Tomonori 		break;
2903639db475SFUJITA Tomonori 	case MODE_SELECT_10:
2904639db475SFUJITA Tomonori 		errsts = resp_mode_select(SCpnt, 0, devip);
2905639db475SFUJITA Tomonori 		break;
2906639db475SFUJITA Tomonori 	case LOG_SENSE:
2907639db475SFUJITA Tomonori 		errsts = resp_log_sense(SCpnt, devip);
2908639db475SFUJITA Tomonori 		break;
2909639db475SFUJITA Tomonori 	case SYNCHRONIZE_CACHE:
2910639db475SFUJITA Tomonori 		delay_override = 1;
2911639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
2912639db475SFUJITA Tomonori 		break;
2913639db475SFUJITA Tomonori 	case WRITE_BUFFER:
2914639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2915639db475SFUJITA Tomonori 		break;
2916639db475SFUJITA Tomonori 	case XDWRITEREAD_10:
2917639db475SFUJITA Tomonori 		if (!scsi_bidi_cmnd(SCpnt)) {
2918639db475SFUJITA Tomonori 			mk_sense_buffer(devip, ILLEGAL_REQUEST,
2919639db475SFUJITA Tomonori 					INVALID_FIELD_IN_CDB, 0);
2920639db475SFUJITA Tomonori 			errsts = check_condition_result;
2921639db475SFUJITA Tomonori 			break;
2922639db475SFUJITA Tomonori 		}
2923639db475SFUJITA Tomonori 
2924639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 0, devip);
2925639db475SFUJITA Tomonori 		if (errsts)
2926639db475SFUJITA Tomonori 			break;
2927639db475SFUJITA Tomonori 		if (scsi_debug_fake_rw)
2928639db475SFUJITA Tomonori 			break;
2929639db475SFUJITA Tomonori 		get_data_transfer_info(cmd, &lba, &num);
2930639db475SFUJITA Tomonori 		errsts = resp_read(SCpnt, lba, num, devip);
2931639db475SFUJITA Tomonori 		if (errsts)
2932639db475SFUJITA Tomonori 			break;
2933639db475SFUJITA Tomonori 		errsts = resp_write(SCpnt, lba, num, devip);
2934639db475SFUJITA Tomonori 		if (errsts)
2935639db475SFUJITA Tomonori 			break;
2936639db475SFUJITA Tomonori 		errsts = resp_xdwriteread(SCpnt, lba, num, devip);
2937639db475SFUJITA Tomonori 		break;
2938639db475SFUJITA Tomonori 	default:
2939639db475SFUJITA Tomonori 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2940639db475SFUJITA Tomonori 			printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
2941639db475SFUJITA Tomonori 			       "supported\n", *cmd);
2942639db475SFUJITA Tomonori 		errsts = check_readiness(SCpnt, 1, devip);
2943639db475SFUJITA Tomonori 		if (errsts)
2944639db475SFUJITA Tomonori 			break;	/* Unit attention takes precedence */
2945639db475SFUJITA Tomonori 		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
2946639db475SFUJITA Tomonori 		errsts = check_condition_result;
2947639db475SFUJITA Tomonori 		break;
2948639db475SFUJITA Tomonori 	}
2949639db475SFUJITA Tomonori 	return schedule_resp(SCpnt, devip, done, errsts,
2950639db475SFUJITA Tomonori 			     (delay_override ? 0 : scsi_debug_delay));
2951639db475SFUJITA Tomonori }
2952639db475SFUJITA Tomonori 
29539e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
29549e603ca0SFUJITA Tomonori 	.proc_info =		scsi_debug_proc_info,
29559e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
29569e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
29579e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
29589e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
29599e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
29609e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
29619e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
29629e603ca0SFUJITA Tomonori 	.queuecommand =		scsi_debug_queuecommand,
29639e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
29649e603ca0SFUJITA Tomonori 	.eh_bus_reset_handler = scsi_debug_bus_reset,
29659e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
29669e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
29679e603ca0SFUJITA Tomonori 	.bios_param =		scsi_debug_biosparam,
29689e603ca0SFUJITA Tomonori 	.can_queue =		SCSI_DEBUG_CANQUEUE,
29699e603ca0SFUJITA Tomonori 	.this_id =		7,
29709e603ca0SFUJITA Tomonori 	.sg_tablesize =		256,
29719e603ca0SFUJITA Tomonori 	.cmd_per_lun =		16,
29729e603ca0SFUJITA Tomonori 	.max_sectors =		0xffff,
29739e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
29749e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
29759e603ca0SFUJITA Tomonori };
29769e603ca0SFUJITA Tomonori 
29771da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev)
29781da177e4SLinus Torvalds {
29791da177e4SLinus Torvalds         int error = 0;
29801da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
29811da177e4SLinus Torvalds         struct Scsi_Host *hpnt;
29821da177e4SLinus Torvalds 
29831da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
29841da177e4SLinus Torvalds 
29851da177e4SLinus Torvalds         hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
29861da177e4SLinus Torvalds         if (NULL == hpnt) {
29871da177e4SLinus Torvalds                 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
29881da177e4SLinus Torvalds                 error = -ENODEV;
29891da177e4SLinus Torvalds 		return error;
29901da177e4SLinus Torvalds         }
29911da177e4SLinus Torvalds 
29921da177e4SLinus Torvalds         sdbg_host->shost = hpnt;
29931da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
29941da177e4SLinus Torvalds 	if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
29951da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts + 1;
29961da177e4SLinus Torvalds 	else
29971da177e4SLinus Torvalds 		hpnt->max_id = scsi_debug_num_tgts;
2998c65b1445SDouglas Gilbert 	hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;	/* = scsi_debug_max_luns; */
29991da177e4SLinus Torvalds 
30001da177e4SLinus Torvalds         error = scsi_add_host(hpnt, &sdbg_host->dev);
30011da177e4SLinus Torvalds         if (error) {
30021da177e4SLinus Torvalds                 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
30031da177e4SLinus Torvalds                 error = -ENODEV;
30041da177e4SLinus Torvalds 		scsi_host_put(hpnt);
30051da177e4SLinus Torvalds         } else
30061da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
30071da177e4SLinus Torvalds 
30081da177e4SLinus Torvalds 
30091da177e4SLinus Torvalds         return error;
30101da177e4SLinus Torvalds }
30111da177e4SLinus Torvalds 
30121da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev)
30131da177e4SLinus Torvalds {
30141da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
30158b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
30161da177e4SLinus Torvalds 
30171da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
30181da177e4SLinus Torvalds 
30191da177e4SLinus Torvalds 	if (!sdbg_host) {
30201da177e4SLinus Torvalds 		printk(KERN_ERR "%s: Unable to locate host info\n",
30211da177e4SLinus Torvalds 		       __FUNCTION__);
30221da177e4SLinus Torvalds 		return -ENODEV;
30231da177e4SLinus Torvalds 	}
30241da177e4SLinus Torvalds 
30251da177e4SLinus Torvalds         scsi_remove_host(sdbg_host->shost);
30261da177e4SLinus Torvalds 
30278b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
30288b40228fSFUJITA Tomonori 				 dev_list) {
30291da177e4SLinus Torvalds                 list_del(&sdbg_devinfo->dev_list);
30301da177e4SLinus Torvalds                 kfree(sdbg_devinfo);
30311da177e4SLinus Torvalds         }
30321da177e4SLinus Torvalds 
30331da177e4SLinus Torvalds         scsi_host_put(sdbg_host->shost);
30341da177e4SLinus Torvalds         return 0;
30351da177e4SLinus Torvalds }
30361da177e4SLinus Torvalds 
30371da177e4SLinus Torvalds static void sdebug_max_tgts_luns(void)
30381da177e4SLinus Torvalds {
30391da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
30401da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
30411da177e4SLinus Torvalds 
30421da177e4SLinus Torvalds 	spin_lock(&sdebug_host_list_lock);
30431da177e4SLinus Torvalds 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
30441da177e4SLinus Torvalds 		hpnt = sdbg_host->shost;
30451da177e4SLinus Torvalds 		if ((hpnt->this_id >= 0) &&
30461da177e4SLinus Torvalds 		    (scsi_debug_num_tgts > hpnt->this_id))
30471da177e4SLinus Torvalds 			hpnt->max_id = scsi_debug_num_tgts + 1;
30481da177e4SLinus Torvalds 		else
30491da177e4SLinus Torvalds 			hpnt->max_id = scsi_debug_num_tgts;
3050c65b1445SDouglas Gilbert 		hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
30511da177e4SLinus Torvalds 	}
30521da177e4SLinus Torvalds 	spin_unlock(&sdebug_host_list_lock);
30531da177e4SLinus Torvalds }
3054