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/sched.h> 321da177e4SLinus Torvalds #include <linux/errno.h> 331da177e4SLinus Torvalds #include <linux/timer.h> 341da177e4SLinus Torvalds #include <linux/types.h> 351da177e4SLinus Torvalds #include <linux/string.h> 361da177e4SLinus Torvalds #include <linux/genhd.h> 371da177e4SLinus Torvalds #include <linux/fs.h> 381da177e4SLinus Torvalds #include <linux/init.h> 391da177e4SLinus Torvalds #include <linux/proc_fs.h> 401da177e4SLinus Torvalds #include <linux/smp_lock.h> 411da177e4SLinus Torvalds #include <linux/vmalloc.h> 421da177e4SLinus Torvalds #include <linux/moduleparam.h> 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds #include <linux/blkdev.h> 451da177e4SLinus Torvalds #include "scsi.h" 461da177e4SLinus Torvalds #include <scsi/scsi_host.h> 471da177e4SLinus Torvalds #include <scsi/scsicam.h> 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds #include <linux/stat.h> 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds #include "scsi_logging.h" 521da177e4SLinus Torvalds #include "scsi_debug.h" 531da177e4SLinus Torvalds 5423183910SDouglas Gilbert #define SCSI_DEBUG_VERSION "1.80" 5523183910SDouglas Gilbert static const char * scsi_debug_version_date = "20060914"; 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds /* Additional Sense Code (ASC) used */ 58c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0 59c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4 601da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11 61c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a 621da177e4SLinus Torvalds #define INVALID_OPCODE 0x20 631da177e4SLinus Torvalds #define ADDR_OUT_OF_RANGE 0x21 641da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24 65c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26 661da177e4SLinus Torvalds #define POWERON_RESET 0x29 671da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39 68c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d 69c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds #define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */ 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds /* Default values for driver parameters */ 741da177e4SLinus Torvalds #define DEF_NUM_HOST 1 751da177e4SLinus Torvalds #define DEF_NUM_TGTS 1 761da177e4SLinus Torvalds #define DEF_MAX_LUNS 1 771da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target 781da177e4SLinus Torvalds * (id 0) containing 1 logical unit (lun 0). That is 1 device. 791da177e4SLinus Torvalds */ 801da177e4SLinus Torvalds #define DEF_DELAY 1 811da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB 8 821da177e4SLinus Torvalds #define DEF_EVERY_NTH 0 831da177e4SLinus Torvalds #define DEF_NUM_PARTS 0 841da177e4SLinus Torvalds #define DEF_OPTS 0 851da177e4SLinus Torvalds #define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */ 861da177e4SLinus Torvalds #define DEF_PTYPE 0 871da177e4SLinus Torvalds #define DEF_D_SENSE 0 88c65b1445SDouglas Gilbert #define DEF_NO_LUN_0 0 89c65b1445SDouglas Gilbert #define DEF_VIRTUAL_GB 0 9023183910SDouglas Gilbert #define DEF_FAKE_RW 0 9123183910SDouglas Gilbert #define DEF_VPD_USE_HOSTNO 1 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */ 941da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE 1 951da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR 2 961da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT 4 971da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR 8 981da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands: 991da177e4SLinus Torvalds * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set 1001da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 1011da177e4SLinus Torvalds * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. 1021da177e4SLinus Torvalds * 1031da177e4SLinus Torvalds * When "every_nth" < 0 then after "- every_nth" commands: 1041da177e4SLinus Torvalds * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set 1051da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 1061da177e4SLinus Torvalds * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. 1071da177e4SLinus Torvalds * This will continue until some other action occurs (e.g. the user 1081da177e4SLinus Torvalds * writing a new value (other than -1 or 1) to every_nth via sysfs). 1091da177e4SLinus Torvalds */ 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this 1121da177e4SLinus Torvalds * sector on read commands: */ 1131da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) 1161da177e4SLinus Torvalds * or "peripheral device" addressing (value 0) */ 1171da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0 118c65b1445SDouglas Gilbert #define SAM2_WLUN_REPORT_LUNS 0xc101 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST; 1211da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY; 1221da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB; 1231da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH; 1241da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS; 1251da177e4SLinus Torvalds static int scsi_debug_num_parts = DEF_NUM_PARTS; 1261da177e4SLinus Torvalds static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 1271da177e4SLinus Torvalds static int scsi_debug_opts = DEF_OPTS; 1281da177e4SLinus Torvalds static int scsi_debug_scsi_level = DEF_SCSI_LEVEL; 1291da177e4SLinus Torvalds static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */ 1301da177e4SLinus Torvalds static int scsi_debug_dsense = DEF_D_SENSE; 131c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0; 132c65b1445SDouglas Gilbert static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; 13323183910SDouglas Gilbert static int scsi_debug_fake_rw = DEF_FAKE_RW; 13423183910SDouglas Gilbert static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds static int scsi_debug_cmnd_count = 0; 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds #define DEV_READONLY(TGT) (0) 1391da177e4SLinus Torvalds #define DEV_REMOVEABLE(TGT) (0) 1401da177e4SLinus Torvalds 141c65b1445SDouglas Gilbert static unsigned int sdebug_store_size; /* in bytes */ 142c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 1431da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 1461da177e4SLinus Torvalds may still need them */ 1471da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 1481da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 1491da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds /* default sector size is 512 bytes, 2**9 bytes */ 1521da177e4SLinus Torvalds #define POW2_SECT_SIZE 9 1531da177e4SLinus Torvalds #define SECT_SIZE (1 << POW2_SECT_SIZE) 1541da177e4SLinus Torvalds #define SECT_SIZE_PER(TGT) SECT_SIZE 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds #define SDEBUG_SENSE_LEN 32 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds struct sdebug_dev_info { 1611da177e4SLinus Torvalds struct list_head dev_list; 1621da177e4SLinus Torvalds unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */ 1631da177e4SLinus Torvalds unsigned int channel; 1641da177e4SLinus Torvalds unsigned int target; 1651da177e4SLinus Torvalds unsigned int lun; 1661da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 167c65b1445SDouglas Gilbert unsigned int wlun; 1681da177e4SLinus Torvalds char reset; 169c65b1445SDouglas Gilbert char stopped; 1701da177e4SLinus Torvalds char used; 1711da177e4SLinus Torvalds }; 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds struct sdebug_host_info { 1741da177e4SLinus Torvalds struct list_head host_list; 1751da177e4SLinus Torvalds struct Scsi_Host *shost; 1761da177e4SLinus Torvalds struct device dev; 1771da177e4SLinus Torvalds struct list_head dev_info_list; 1781da177e4SLinus Torvalds }; 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds #define to_sdebug_host(d) \ 1811da177e4SLinus Torvalds container_of(d, struct sdebug_host_info, dev) 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 1841da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 1851da177e4SLinus Torvalds 1861da177e4SLinus Torvalds typedef void (* done_funct_t) (struct scsi_cmnd *); 1871da177e4SLinus Torvalds 1881da177e4SLinus Torvalds struct sdebug_queued_cmd { 1891da177e4SLinus Torvalds int in_use; 1901da177e4SLinus Torvalds struct timer_list cmnd_timer; 1911da177e4SLinus Torvalds done_funct_t done_funct; 1921da177e4SLinus Torvalds struct scsi_cmnd * a_cmnd; 1931da177e4SLinus Torvalds int scsi_result; 1941da177e4SLinus Torvalds }; 1951da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; 1961da177e4SLinus Torvalds 197d0be4a7dSChristoph Hellwig static struct scsi_host_template sdebug_driver_template = { 1981da177e4SLinus Torvalds .proc_info = scsi_debug_proc_info, 1991da177e4SLinus Torvalds .name = "SCSI DEBUG", 2001da177e4SLinus Torvalds .info = scsi_debug_info, 2011da177e4SLinus Torvalds .slave_alloc = scsi_debug_slave_alloc, 2021da177e4SLinus Torvalds .slave_configure = scsi_debug_slave_configure, 2031da177e4SLinus Torvalds .slave_destroy = scsi_debug_slave_destroy, 2041da177e4SLinus Torvalds .ioctl = scsi_debug_ioctl, 2051da177e4SLinus Torvalds .queuecommand = scsi_debug_queuecommand, 2061da177e4SLinus Torvalds .eh_abort_handler = scsi_debug_abort, 2071da177e4SLinus Torvalds .eh_bus_reset_handler = scsi_debug_bus_reset, 2081da177e4SLinus Torvalds .eh_device_reset_handler = scsi_debug_device_reset, 2091da177e4SLinus Torvalds .eh_host_reset_handler = scsi_debug_host_reset, 2101da177e4SLinus Torvalds .bios_param = scsi_debug_biosparam, 2111da177e4SLinus Torvalds .can_queue = SCSI_DEBUG_CANQUEUE, 2121da177e4SLinus Torvalds .this_id = 7, 213c65b1445SDouglas Gilbert .sg_tablesize = 256, 214c65b1445SDouglas Gilbert .cmd_per_lun = 16, 215c65b1445SDouglas Gilbert .max_sectors = 0xffff, 2161da177e4SLinus Torvalds .unchecked_isa_dma = 0, 217c65b1445SDouglas Gilbert .use_clustering = ENABLE_CLUSTERING, 2181da177e4SLinus Torvalds .module = THIS_MODULE, 2191da177e4SLinus Torvalds }; 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds static unsigned char * fake_storep; /* ramdisk storage */ 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds static int num_aborts = 0; 2241da177e4SLinus Torvalds static int num_dev_resets = 0; 2251da177e4SLinus Torvalds static int num_bus_resets = 0; 2261da177e4SLinus Torvalds static int num_host_resets = 0; 2271da177e4SLinus Torvalds 2281da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock); 2291da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds static char sdebug_proc_name[] = "scsi_debug"; 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *); 2341da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *); 2351da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 2381da177e4SLinus Torvalds .name = sdebug_proc_name, 2391da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 2401da177e4SLinus Torvalds }; 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds static const int check_condition_result = 2431da177e4SLinus Torvalds (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 2441da177e4SLinus Torvalds 245c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 246c65b1445SDouglas Gilbert 0, 0, 0x2, 0x4b}; 247c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 248c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 249c65b1445SDouglas Gilbert 2501da177e4SLinus Torvalds /* function declarations */ 2511da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd * SCpnt, int target, 2521da177e4SLinus Torvalds struct sdebug_dev_info * devip); 2531da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * SCpnt, 2541da177e4SLinus Torvalds struct sdebug_dev_info * devip); 255c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp, 256c65b1445SDouglas Gilbert struct sdebug_dev_info * devip); 2571da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * SCpnt, 2581da177e4SLinus Torvalds struct sdebug_dev_info * devip); 259c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * SCpnt, 2601da177e4SLinus Torvalds struct sdebug_dev_info * devip); 261c65b1445SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd * scp, int target, 262c65b1445SDouglas Gilbert struct sdebug_dev_info * devip); 263c65b1445SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd * scp, int mselect6, 264c65b1445SDouglas Gilbert struct sdebug_dev_info * devip); 265c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp, 266c65b1445SDouglas Gilbert struct sdebug_dev_info * devip); 267c65b1445SDouglas Gilbert static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba, 268c65b1445SDouglas Gilbert unsigned int num, struct sdebug_dev_info * devip); 269c65b1445SDouglas Gilbert static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba, 270c65b1445SDouglas Gilbert unsigned int num, struct sdebug_dev_info * devip); 2711da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * SCpnt, 2721da177e4SLinus Torvalds struct sdebug_dev_info * devip); 2731da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, 2741da177e4SLinus Torvalds int arr_len); 2751da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, 2761da177e4SLinus Torvalds int max_arr_len); 2771da177e4SLinus Torvalds static void timer_intr_handler(unsigned long); 2781da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev); 2791da177e4SLinus Torvalds static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, 2801da177e4SLinus Torvalds int asc, int asq); 281c65b1445SDouglas Gilbert static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only, 2821da177e4SLinus Torvalds struct sdebug_dev_info * devip); 2831da177e4SLinus Torvalds static int schedule_resp(struct scsi_cmnd * cmnd, 2841da177e4SLinus Torvalds struct sdebug_dev_info * devip, 2851da177e4SLinus Torvalds done_funct_t done, int scsi_result, int delta_jiff); 2861da177e4SLinus Torvalds static void __init sdebug_build_parts(unsigned char * ramp); 2871da177e4SLinus Torvalds static void __init init_all_queued(void); 2881da177e4SLinus Torvalds static void stop_all_queued(void); 2891da177e4SLinus Torvalds static int stop_queued_cmnd(struct scsi_cmnd * cmnd); 290c65b1445SDouglas Gilbert static int inquiry_evpd_83(unsigned char * arr, int target_dev_id, 291c65b1445SDouglas Gilbert int dev_id_num, const char * dev_id_str, 292c65b1445SDouglas Gilbert int dev_id_str_len); 293c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id); 2946ecaff7fSRandy Dunlap static int do_create_driverfs_files(void); 2951da177e4SLinus Torvalds static void do_remove_driverfs_files(void); 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds static int sdebug_add_adapter(void); 2981da177e4SLinus Torvalds static void sdebug_remove_adapter(void); 2991da177e4SLinus Torvalds static void sdebug_max_tgts_luns(void); 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds static struct device pseudo_primary; 3021da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 3031da177e4SLinus Torvalds 3041da177e4SLinus Torvalds 3051da177e4SLinus Torvalds static 3061da177e4SLinus Torvalds int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) 3071da177e4SLinus Torvalds { 3081da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *) SCpnt->cmnd; 309c65b1445SDouglas Gilbert int len, k, j; 310c65b1445SDouglas Gilbert unsigned int num; 311c65b1445SDouglas Gilbert unsigned long long lba; 3121da177e4SLinus Torvalds int errsts = 0; 313c65b1445SDouglas Gilbert int target = SCpnt->device->id; 3141da177e4SLinus Torvalds struct sdebug_dev_info * devip = NULL; 3151da177e4SLinus Torvalds int inj_recovered = 0; 316c65b1445SDouglas Gilbert int delay_override = 0; 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds if (done == NULL) 3191da177e4SLinus Torvalds return 0; /* assume mid level reprocessing command */ 3201da177e4SLinus Torvalds 321c65b1445SDouglas Gilbert SCpnt->resid = 0; 3221da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { 3231da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: cmd "); 324c65b1445SDouglas Gilbert for (k = 0, len = SCpnt->cmd_len; k < len; ++k) 3251da177e4SLinus Torvalds printk("%02x ", (int)cmd[k]); 3261da177e4SLinus Torvalds printk("\n"); 3271da177e4SLinus Torvalds } 3281da177e4SLinus Torvalds if(target == sdebug_driver_template.this_id) { 3291da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: initiator's id used as " 3301da177e4SLinus Torvalds "target!\n"); 3311da177e4SLinus Torvalds return schedule_resp(SCpnt, NULL, done, 3321da177e4SLinus Torvalds DID_NO_CONNECT << 16, 0); 3331da177e4SLinus Torvalds } 3341da177e4SLinus Torvalds 335c65b1445SDouglas Gilbert if ((SCpnt->device->lun >= scsi_debug_max_luns) && 336c65b1445SDouglas Gilbert (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS)) 3371da177e4SLinus Torvalds return schedule_resp(SCpnt, NULL, done, 3381da177e4SLinus Torvalds DID_NO_CONNECT << 16, 0); 3391da177e4SLinus Torvalds devip = devInfoReg(SCpnt->device); 3401da177e4SLinus Torvalds if (NULL == devip) 3411da177e4SLinus Torvalds return schedule_resp(SCpnt, NULL, done, 3421da177e4SLinus Torvalds DID_NO_CONNECT << 16, 0); 3431da177e4SLinus Torvalds 3441da177e4SLinus Torvalds if ((scsi_debug_every_nth != 0) && 3451da177e4SLinus Torvalds (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) { 3461da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 3471da177e4SLinus Torvalds if (scsi_debug_every_nth < -1) 3481da177e4SLinus Torvalds scsi_debug_every_nth = -1; 3491da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts) 3501da177e4SLinus Torvalds return 0; /* ignore command causing timeout */ 3511da177e4SLinus Torvalds else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts) 3521da177e4SLinus Torvalds inj_recovered = 1; /* to reads and writes below */ 3531da177e4SLinus Torvalds } 3541da177e4SLinus Torvalds 355c65b1445SDouglas Gilbert if (devip->wlun) { 356c65b1445SDouglas Gilbert switch (*cmd) { 357c65b1445SDouglas Gilbert case INQUIRY: 358c65b1445SDouglas Gilbert case REQUEST_SENSE: 359c65b1445SDouglas Gilbert case TEST_UNIT_READY: 360c65b1445SDouglas Gilbert case REPORT_LUNS: 361c65b1445SDouglas Gilbert break; /* only allowable wlun commands */ 362c65b1445SDouglas Gilbert default: 363c65b1445SDouglas Gilbert if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 364c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: Opcode: 0x%x " 365c65b1445SDouglas Gilbert "not supported for wlun\n", *cmd); 366c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 367c65b1445SDouglas Gilbert INVALID_OPCODE, 0); 368c65b1445SDouglas Gilbert errsts = check_condition_result; 369c65b1445SDouglas Gilbert return schedule_resp(SCpnt, devip, done, errsts, 370c65b1445SDouglas Gilbert 0); 371c65b1445SDouglas Gilbert } 372c65b1445SDouglas Gilbert } 373c65b1445SDouglas Gilbert 3741da177e4SLinus Torvalds switch (*cmd) { 3751da177e4SLinus Torvalds case INQUIRY: /* mandatory, ignore unit attention */ 376c65b1445SDouglas Gilbert delay_override = 1; 3771da177e4SLinus Torvalds errsts = resp_inquiry(SCpnt, target, devip); 3781da177e4SLinus Torvalds break; 3791da177e4SLinus Torvalds case REQUEST_SENSE: /* mandatory, ignore unit attention */ 380c65b1445SDouglas Gilbert delay_override = 1; 3811da177e4SLinus Torvalds errsts = resp_requests(SCpnt, devip); 3821da177e4SLinus Torvalds break; 3831da177e4SLinus Torvalds case REZERO_UNIT: /* actually this is REWIND for SSC */ 3841da177e4SLinus Torvalds case START_STOP: 385c65b1445SDouglas Gilbert errsts = resp_start_stop(SCpnt, devip); 3861da177e4SLinus Torvalds break; 3871da177e4SLinus Torvalds case ALLOW_MEDIUM_REMOVAL: 388c65b1445SDouglas Gilbert if ((errsts = check_readiness(SCpnt, 1, devip))) 3891da177e4SLinus Torvalds break; 3901da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3911da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: Medium removal %s\n", 3921da177e4SLinus Torvalds cmd[4] ? "inhibited" : "enabled"); 3931da177e4SLinus Torvalds break; 3941da177e4SLinus Torvalds case SEND_DIAGNOSTIC: /* mandatory */ 395c65b1445SDouglas Gilbert errsts = check_readiness(SCpnt, 1, devip); 3961da177e4SLinus Torvalds break; 3971da177e4SLinus Torvalds case TEST_UNIT_READY: /* mandatory */ 398c65b1445SDouglas Gilbert delay_override = 1; 399c65b1445SDouglas Gilbert errsts = check_readiness(SCpnt, 0, devip); 4001da177e4SLinus Torvalds break; 4011da177e4SLinus Torvalds case RESERVE: 402c65b1445SDouglas Gilbert errsts = check_readiness(SCpnt, 1, devip); 4031da177e4SLinus Torvalds break; 4041da177e4SLinus Torvalds case RESERVE_10: 405c65b1445SDouglas Gilbert errsts = check_readiness(SCpnt, 1, devip); 4061da177e4SLinus Torvalds break; 4071da177e4SLinus Torvalds case RELEASE: 408c65b1445SDouglas Gilbert errsts = check_readiness(SCpnt, 1, devip); 4091da177e4SLinus Torvalds break; 4101da177e4SLinus Torvalds case RELEASE_10: 411c65b1445SDouglas Gilbert errsts = check_readiness(SCpnt, 1, devip); 4121da177e4SLinus Torvalds break; 4131da177e4SLinus Torvalds case READ_CAPACITY: 4141da177e4SLinus Torvalds errsts = resp_readcap(SCpnt, devip); 4151da177e4SLinus Torvalds break; 416c65b1445SDouglas Gilbert case SERVICE_ACTION_IN: 417c65b1445SDouglas Gilbert if (SAI_READ_CAPACITY_16 != cmd[1]) { 418c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 419c65b1445SDouglas Gilbert INVALID_OPCODE, 0); 420c65b1445SDouglas Gilbert errsts = check_condition_result; 421c65b1445SDouglas Gilbert break; 422c65b1445SDouglas Gilbert } 423c65b1445SDouglas Gilbert errsts = resp_readcap16(SCpnt, devip); 424c65b1445SDouglas Gilbert break; 4251da177e4SLinus Torvalds case READ_16: 4261da177e4SLinus Torvalds case READ_12: 4271da177e4SLinus Torvalds case READ_10: 4281da177e4SLinus Torvalds case READ_6: 429c65b1445SDouglas Gilbert if ((errsts = check_readiness(SCpnt, 0, devip))) 4301da177e4SLinus Torvalds break; 43123183910SDouglas Gilbert if (scsi_debug_fake_rw) 43223183910SDouglas Gilbert break; 4331da177e4SLinus Torvalds if ((*cmd) == READ_16) { 434c65b1445SDouglas Gilbert for (lba = 0, j = 0; j < 8; ++j) { 435c65b1445SDouglas Gilbert if (j > 0) 436c65b1445SDouglas Gilbert lba <<= 8; 437c65b1445SDouglas Gilbert lba += cmd[2 + j]; 438c65b1445SDouglas Gilbert } 4391da177e4SLinus Torvalds num = cmd[13] + (cmd[12] << 8) + 4401da177e4SLinus Torvalds (cmd[11] << 16) + (cmd[10] << 24); 4411da177e4SLinus Torvalds } else if ((*cmd) == READ_12) { 442c65b1445SDouglas Gilbert lba = cmd[5] + (cmd[4] << 8) + 4431da177e4SLinus Torvalds (cmd[3] << 16) + (cmd[2] << 24); 4441da177e4SLinus Torvalds num = cmd[9] + (cmd[8] << 8) + 4451da177e4SLinus Torvalds (cmd[7] << 16) + (cmd[6] << 24); 4461da177e4SLinus Torvalds } else if ((*cmd) == READ_10) { 447c65b1445SDouglas Gilbert lba = cmd[5] + (cmd[4] << 8) + 4481da177e4SLinus Torvalds (cmd[3] << 16) + (cmd[2] << 24); 4491da177e4SLinus Torvalds num = cmd[8] + (cmd[7] << 8); 450c65b1445SDouglas Gilbert } else { /* READ (6) */ 451c65b1445SDouglas Gilbert lba = cmd[3] + (cmd[2] << 8) + 4521da177e4SLinus Torvalds ((cmd[1] & 0x1f) << 16); 453c65b1445SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 4541da177e4SLinus Torvalds } 455c65b1445SDouglas Gilbert errsts = resp_read(SCpnt, lba, num, devip); 4561da177e4SLinus Torvalds if (inj_recovered && (0 == errsts)) { 4571da177e4SLinus Torvalds mk_sense_buffer(devip, RECOVERED_ERROR, 458c65b1445SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 4591da177e4SLinus Torvalds errsts = check_condition_result; 4601da177e4SLinus Torvalds } 4611da177e4SLinus Torvalds break; 4621da177e4SLinus Torvalds case REPORT_LUNS: /* mandatory, ignore unit attention */ 463c65b1445SDouglas Gilbert delay_override = 1; 4641da177e4SLinus Torvalds errsts = resp_report_luns(SCpnt, devip); 4651da177e4SLinus Torvalds break; 4661da177e4SLinus Torvalds case VERIFY: /* 10 byte SBC-2 command */ 467c65b1445SDouglas Gilbert errsts = check_readiness(SCpnt, 0, devip); 4681da177e4SLinus Torvalds break; 4691da177e4SLinus Torvalds case WRITE_16: 4701da177e4SLinus Torvalds case WRITE_12: 4711da177e4SLinus Torvalds case WRITE_10: 4721da177e4SLinus Torvalds case WRITE_6: 473c65b1445SDouglas Gilbert if ((errsts = check_readiness(SCpnt, 0, devip))) 4741da177e4SLinus Torvalds break; 47523183910SDouglas Gilbert if (scsi_debug_fake_rw) 47623183910SDouglas Gilbert break; 4771da177e4SLinus Torvalds if ((*cmd) == WRITE_16) { 478c65b1445SDouglas Gilbert for (lba = 0, j = 0; j < 8; ++j) { 479c65b1445SDouglas Gilbert if (j > 0) 480c65b1445SDouglas Gilbert lba <<= 8; 481c65b1445SDouglas Gilbert lba += cmd[2 + j]; 482c65b1445SDouglas Gilbert } 4831da177e4SLinus Torvalds num = cmd[13] + (cmd[12] << 8) + 4841da177e4SLinus Torvalds (cmd[11] << 16) + (cmd[10] << 24); 4851da177e4SLinus Torvalds } else if ((*cmd) == WRITE_12) { 486c65b1445SDouglas Gilbert lba = cmd[5] + (cmd[4] << 8) + 4871da177e4SLinus Torvalds (cmd[3] << 16) + (cmd[2] << 24); 4881da177e4SLinus Torvalds num = cmd[9] + (cmd[8] << 8) + 4891da177e4SLinus Torvalds (cmd[7] << 16) + (cmd[6] << 24); 4901da177e4SLinus Torvalds } else if ((*cmd) == WRITE_10) { 491c65b1445SDouglas Gilbert lba = cmd[5] + (cmd[4] << 8) + 4921da177e4SLinus Torvalds (cmd[3] << 16) + (cmd[2] << 24); 4931da177e4SLinus Torvalds num = cmd[8] + (cmd[7] << 8); 494c65b1445SDouglas Gilbert } else { /* WRITE (6) */ 495c65b1445SDouglas Gilbert lba = cmd[3] + (cmd[2] << 8) + 4961da177e4SLinus Torvalds ((cmd[1] & 0x1f) << 16); 497c65b1445SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 4981da177e4SLinus Torvalds } 499c65b1445SDouglas Gilbert errsts = resp_write(SCpnt, lba, num, devip); 5001da177e4SLinus Torvalds if (inj_recovered && (0 == errsts)) { 5011da177e4SLinus Torvalds mk_sense_buffer(devip, RECOVERED_ERROR, 502c65b1445SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 5031da177e4SLinus Torvalds errsts = check_condition_result; 5041da177e4SLinus Torvalds } 5051da177e4SLinus Torvalds break; 5061da177e4SLinus Torvalds case MODE_SENSE: 5071da177e4SLinus Torvalds case MODE_SENSE_10: 5081da177e4SLinus Torvalds errsts = resp_mode_sense(SCpnt, target, devip); 5091da177e4SLinus Torvalds break; 510c65b1445SDouglas Gilbert case MODE_SELECT: 511c65b1445SDouglas Gilbert errsts = resp_mode_select(SCpnt, 1, devip); 512c65b1445SDouglas Gilbert break; 513c65b1445SDouglas Gilbert case MODE_SELECT_10: 514c65b1445SDouglas Gilbert errsts = resp_mode_select(SCpnt, 0, devip); 515c65b1445SDouglas Gilbert break; 516c65b1445SDouglas Gilbert case LOG_SENSE: 517c65b1445SDouglas Gilbert errsts = resp_log_sense(SCpnt, devip); 518c65b1445SDouglas Gilbert break; 5191da177e4SLinus Torvalds case SYNCHRONIZE_CACHE: 520c65b1445SDouglas Gilbert delay_override = 1; 521c65b1445SDouglas Gilbert errsts = check_readiness(SCpnt, 0, devip); 5221da177e4SLinus Torvalds break; 5231da177e4SLinus Torvalds default: 5241da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 5251da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " 5261da177e4SLinus Torvalds "supported\n", *cmd); 527c65b1445SDouglas Gilbert if ((errsts = check_readiness(SCpnt, 1, devip))) 5281da177e4SLinus Torvalds break; /* Unit attention takes precedence */ 5291da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 5301da177e4SLinus Torvalds errsts = check_condition_result; 5311da177e4SLinus Torvalds break; 5321da177e4SLinus Torvalds } 533c65b1445SDouglas Gilbert return schedule_resp(SCpnt, devip, done, errsts, 534c65b1445SDouglas Gilbert (delay_override ? 0 : scsi_debug_delay)); 5351da177e4SLinus Torvalds } 5361da177e4SLinus Torvalds 5371da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) 5381da177e4SLinus Torvalds { 5391da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { 5401da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd); 5411da177e4SLinus Torvalds } 5421da177e4SLinus Torvalds return -EINVAL; 5431da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 5441da177e4SLinus Torvalds } 5451da177e4SLinus Torvalds 546c65b1445SDouglas Gilbert static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only, 547c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 5481da177e4SLinus Torvalds { 5491da177e4SLinus Torvalds if (devip->reset) { 5501da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 5511da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: Reporting Unit " 5521da177e4SLinus Torvalds "attention: power on reset\n"); 5531da177e4SLinus Torvalds devip->reset = 0; 5541da177e4SLinus Torvalds mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0); 5551da177e4SLinus Torvalds return check_condition_result; 5561da177e4SLinus Torvalds } 557c65b1445SDouglas Gilbert if ((0 == reset_only) && devip->stopped) { 558c65b1445SDouglas Gilbert if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 559c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: Reporting Not " 560c65b1445SDouglas Gilbert "ready: initializing command required\n"); 561c65b1445SDouglas Gilbert mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY, 562c65b1445SDouglas Gilbert 0x2); 563c65b1445SDouglas Gilbert return check_condition_result; 564c65b1445SDouglas Gilbert } 5651da177e4SLinus Torvalds return 0; 5661da177e4SLinus Torvalds } 5671da177e4SLinus Torvalds 5681da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ 5691da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, 5701da177e4SLinus Torvalds int arr_len) 5711da177e4SLinus Torvalds { 5721da177e4SLinus Torvalds int k, req_len, act_len, len, active; 5731da177e4SLinus Torvalds void * kaddr; 5741da177e4SLinus Torvalds void * kaddr_off; 5751da177e4SLinus Torvalds struct scatterlist * sgpnt; 5761da177e4SLinus Torvalds 5771da177e4SLinus Torvalds if (0 == scp->request_bufflen) 5781da177e4SLinus Torvalds return 0; 5791da177e4SLinus Torvalds if (NULL == scp->request_buffer) 5801da177e4SLinus Torvalds return (DID_ERROR << 16); 5811da177e4SLinus Torvalds if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) || 5821da177e4SLinus Torvalds (scp->sc_data_direction == DMA_FROM_DEVICE))) 5831da177e4SLinus Torvalds return (DID_ERROR << 16); 5841da177e4SLinus Torvalds if (0 == scp->use_sg) { 5851da177e4SLinus Torvalds req_len = scp->request_bufflen; 5861da177e4SLinus Torvalds act_len = (req_len < arr_len) ? req_len : arr_len; 5871da177e4SLinus Torvalds memcpy(scp->request_buffer, arr, act_len); 588c65b1445SDouglas Gilbert if (scp->resid) 589c65b1445SDouglas Gilbert scp->resid -= act_len; 590c65b1445SDouglas Gilbert else 5911da177e4SLinus Torvalds scp->resid = req_len - act_len; 5921da177e4SLinus Torvalds return 0; 5931da177e4SLinus Torvalds } 5941da177e4SLinus Torvalds sgpnt = (struct scatterlist *)scp->request_buffer; 5951da177e4SLinus Torvalds active = 1; 5961da177e4SLinus Torvalds for (k = 0, req_len = 0, act_len = 0; k < scp->use_sg; ++k, ++sgpnt) { 5971da177e4SLinus Torvalds if (active) { 5981da177e4SLinus Torvalds kaddr = (unsigned char *) 5991da177e4SLinus Torvalds kmap_atomic(sgpnt->page, KM_USER0); 6001da177e4SLinus Torvalds if (NULL == kaddr) 6011da177e4SLinus Torvalds return (DID_ERROR << 16); 6021da177e4SLinus Torvalds kaddr_off = (unsigned char *)kaddr + sgpnt->offset; 6031da177e4SLinus Torvalds len = sgpnt->length; 6041da177e4SLinus Torvalds if ((req_len + len) > arr_len) { 6051da177e4SLinus Torvalds active = 0; 6061da177e4SLinus Torvalds len = arr_len - req_len; 6071da177e4SLinus Torvalds } 6081da177e4SLinus Torvalds memcpy(kaddr_off, arr + req_len, len); 6091da177e4SLinus Torvalds kunmap_atomic(kaddr, KM_USER0); 6101da177e4SLinus Torvalds act_len += len; 6111da177e4SLinus Torvalds } 6121da177e4SLinus Torvalds req_len += sgpnt->length; 6131da177e4SLinus Torvalds } 614c65b1445SDouglas Gilbert if (scp->resid) 615c65b1445SDouglas Gilbert scp->resid -= act_len; 616c65b1445SDouglas Gilbert else 6171da177e4SLinus Torvalds scp->resid = req_len - act_len; 6181da177e4SLinus Torvalds return 0; 6191da177e4SLinus Torvalds } 6201da177e4SLinus Torvalds 6211da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */ 6221da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, 6231da177e4SLinus Torvalds int max_arr_len) 6241da177e4SLinus Torvalds { 6251da177e4SLinus Torvalds int k, req_len, len, fin; 6261da177e4SLinus Torvalds void * kaddr; 6271da177e4SLinus Torvalds void * kaddr_off; 6281da177e4SLinus Torvalds struct scatterlist * sgpnt; 6291da177e4SLinus Torvalds 6301da177e4SLinus Torvalds if (0 == scp->request_bufflen) 6311da177e4SLinus Torvalds return 0; 6321da177e4SLinus Torvalds if (NULL == scp->request_buffer) 6331da177e4SLinus Torvalds return -1; 6341da177e4SLinus Torvalds if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) || 6351da177e4SLinus Torvalds (scp->sc_data_direction == DMA_TO_DEVICE))) 6361da177e4SLinus Torvalds return -1; 6371da177e4SLinus Torvalds if (0 == scp->use_sg) { 6381da177e4SLinus Torvalds req_len = scp->request_bufflen; 6391da177e4SLinus Torvalds len = (req_len < max_arr_len) ? req_len : max_arr_len; 6401da177e4SLinus Torvalds memcpy(arr, scp->request_buffer, len); 6411da177e4SLinus Torvalds return len; 6421da177e4SLinus Torvalds } 6431da177e4SLinus Torvalds sgpnt = (struct scatterlist *)scp->request_buffer; 6441da177e4SLinus Torvalds for (k = 0, req_len = 0, fin = 0; k < scp->use_sg; ++k, ++sgpnt) { 6451da177e4SLinus Torvalds kaddr = (unsigned char *)kmap_atomic(sgpnt->page, KM_USER0); 6461da177e4SLinus Torvalds if (NULL == kaddr) 6471da177e4SLinus Torvalds return -1; 6481da177e4SLinus Torvalds kaddr_off = (unsigned char *)kaddr + sgpnt->offset; 6491da177e4SLinus Torvalds len = sgpnt->length; 6501da177e4SLinus Torvalds if ((req_len + len) > max_arr_len) { 6511da177e4SLinus Torvalds len = max_arr_len - req_len; 6521da177e4SLinus Torvalds fin = 1; 6531da177e4SLinus Torvalds } 6541da177e4SLinus Torvalds memcpy(arr + req_len, kaddr_off, len); 6551da177e4SLinus Torvalds kunmap_atomic(kaddr, KM_USER0); 6561da177e4SLinus Torvalds if (fin) 6571da177e4SLinus Torvalds return req_len + len; 6581da177e4SLinus Torvalds req_len += sgpnt->length; 6591da177e4SLinus Torvalds } 6601da177e4SLinus Torvalds return req_len; 6611da177e4SLinus Torvalds } 6621da177e4SLinus Torvalds 6631da177e4SLinus Torvalds 6641da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux "; 6651da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug "; 6661da177e4SLinus Torvalds static const char * inq_product_rev = "0004"; 6671da177e4SLinus Torvalds 668c65b1445SDouglas Gilbert static int inquiry_evpd_83(unsigned char * arr, int target_dev_id, 669c65b1445SDouglas Gilbert int dev_id_num, const char * dev_id_str, 670c65b1445SDouglas Gilbert int dev_id_str_len) 6711da177e4SLinus Torvalds { 672c65b1445SDouglas Gilbert int num, port_a; 673c65b1445SDouglas Gilbert char b[32]; 6741da177e4SLinus Torvalds 675c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 6761da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 6771da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 6781da177e4SLinus Torvalds arr[1] = 0x1; 6791da177e4SLinus Torvalds arr[2] = 0x0; 6801da177e4SLinus Torvalds memcpy(&arr[4], inq_vendor_id, 8); 6811da177e4SLinus Torvalds memcpy(&arr[12], inq_product_id, 16); 6821da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 6831da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 6841da177e4SLinus Torvalds arr[3] = num; 6851da177e4SLinus Torvalds num += 4; 686c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 687c65b1445SDouglas Gilbert /* NAA-5, Logical unit identifier (binary) */ 688c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 689c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 690c65b1445SDouglas Gilbert arr[num++] = 0x0; 691c65b1445SDouglas Gilbert arr[num++] = 0x8; 692c65b1445SDouglas Gilbert arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */ 693c65b1445SDouglas Gilbert arr[num++] = 0x33; 694c65b1445SDouglas Gilbert arr[num++] = 0x33; 695c65b1445SDouglas Gilbert arr[num++] = 0x30; 696c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 24); 697c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 16) & 0xff; 698c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 8) & 0xff; 699c65b1445SDouglas Gilbert arr[num++] = dev_id_num & 0xff; 700c65b1445SDouglas Gilbert /* Target relative port number */ 701c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 702c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 703c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 704c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 705c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 706c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 707c65b1445SDouglas Gilbert arr[num++] = 0x0; 708c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 709c65b1445SDouglas Gilbert } 710c65b1445SDouglas Gilbert /* NAA-5, Target port identifier */ 711c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 712c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 713c65b1445SDouglas Gilbert arr[num++] = 0x0; 714c65b1445SDouglas Gilbert arr[num++] = 0x8; 715c65b1445SDouglas Gilbert arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ 716c65b1445SDouglas Gilbert arr[num++] = 0x22; 717c65b1445SDouglas Gilbert arr[num++] = 0x22; 718c65b1445SDouglas Gilbert arr[num++] = 0x20; 719c65b1445SDouglas Gilbert arr[num++] = (port_a >> 24); 720c65b1445SDouglas Gilbert arr[num++] = (port_a >> 16) & 0xff; 721c65b1445SDouglas Gilbert arr[num++] = (port_a >> 8) & 0xff; 722c65b1445SDouglas Gilbert arr[num++] = port_a & 0xff; 723c65b1445SDouglas Gilbert /* NAA-5, Target device identifier */ 724c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 725c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 726c65b1445SDouglas Gilbert arr[num++] = 0x0; 727c65b1445SDouglas Gilbert arr[num++] = 0x8; 728c65b1445SDouglas Gilbert arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ 729c65b1445SDouglas Gilbert arr[num++] = 0x22; 730c65b1445SDouglas Gilbert arr[num++] = 0x22; 731c65b1445SDouglas Gilbert arr[num++] = 0x20; 732c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 24); 733c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 16) & 0xff; 734c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 8) & 0xff; 735c65b1445SDouglas Gilbert arr[num++] = target_dev_id & 0xff; 736c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 737c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 738c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 739c65b1445SDouglas Gilbert arr[num++] = 0x0; 740c65b1445SDouglas Gilbert arr[num++] = 24; 741c65b1445SDouglas Gilbert memcpy(arr + num, "naa.52222220", 12); 742c65b1445SDouglas Gilbert num += 12; 743c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 744c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 745c65b1445SDouglas Gilbert num += 8; 746c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 747c65b1445SDouglas Gilbert num += 4; 748c65b1445SDouglas Gilbert return num; 749c65b1445SDouglas Gilbert } 750c65b1445SDouglas Gilbert 751c65b1445SDouglas Gilbert 752c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 753c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 754c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 755c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 756c65b1445SDouglas Gilbert }; 757c65b1445SDouglas Gilbert 758c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr) 759c65b1445SDouglas Gilbert { 760c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 761c65b1445SDouglas Gilbert return sizeof(vpd84_data); 762c65b1445SDouglas Gilbert } 763c65b1445SDouglas Gilbert 764c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr) 765c65b1445SDouglas Gilbert { 766c65b1445SDouglas Gilbert int num = 0; 767c65b1445SDouglas Gilbert const char * na1 = "https://www.kernel.org/config"; 768c65b1445SDouglas Gilbert const char * na2 = "http://www.kernel.org/log"; 769c65b1445SDouglas Gilbert int plen, olen; 770c65b1445SDouglas Gilbert 771c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 772c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 773c65b1445SDouglas Gilbert arr[num++] = 0x0; 774c65b1445SDouglas Gilbert olen = strlen(na1); 775c65b1445SDouglas Gilbert plen = olen + 1; 776c65b1445SDouglas Gilbert if (plen % 4) 777c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 778c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 779c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 780c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 781c65b1445SDouglas Gilbert num += plen; 782c65b1445SDouglas Gilbert 783c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 784c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 785c65b1445SDouglas Gilbert arr[num++] = 0x0; 786c65b1445SDouglas Gilbert olen = strlen(na2); 787c65b1445SDouglas Gilbert plen = olen + 1; 788c65b1445SDouglas Gilbert if (plen % 4) 789c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 790c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 791c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 792c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 793c65b1445SDouglas Gilbert num += plen; 794c65b1445SDouglas Gilbert 795c65b1445SDouglas Gilbert return num; 796c65b1445SDouglas Gilbert } 797c65b1445SDouglas Gilbert 798c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 799c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id) 800c65b1445SDouglas Gilbert { 801c65b1445SDouglas Gilbert int num = 0; 802c65b1445SDouglas Gilbert int port_a, port_b; 803c65b1445SDouglas Gilbert 804c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 805c65b1445SDouglas Gilbert port_b = port_a + 1; 806c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 807c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 808c65b1445SDouglas Gilbert arr[num++] = 0x0; 809c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 810c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 811c65b1445SDouglas Gilbert num += 6; 812c65b1445SDouglas Gilbert arr[num++] = 0x0; 813c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 814c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 815c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 816c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 817c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 818c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 819c65b1445SDouglas Gilbert arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ 820c65b1445SDouglas Gilbert arr[num++] = 0x22; 821c65b1445SDouglas Gilbert arr[num++] = 0x22; 822c65b1445SDouglas Gilbert arr[num++] = 0x20; 823c65b1445SDouglas Gilbert arr[num++] = (port_a >> 24); 824c65b1445SDouglas Gilbert arr[num++] = (port_a >> 16) & 0xff; 825c65b1445SDouglas Gilbert arr[num++] = (port_a >> 8) & 0xff; 826c65b1445SDouglas Gilbert arr[num++] = port_a & 0xff; 827c65b1445SDouglas Gilbert 828c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 829c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 830c65b1445SDouglas Gilbert arr[num++] = 0x0; 831c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 832c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 833c65b1445SDouglas Gilbert num += 6; 834c65b1445SDouglas Gilbert arr[num++] = 0x0; 835c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 836c65b1445SDouglas Gilbert /* naa-5 target port identifier (B) */ 837c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 838c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 839c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 840c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 841c65b1445SDouglas Gilbert arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ 842c65b1445SDouglas Gilbert arr[num++] = 0x22; 843c65b1445SDouglas Gilbert arr[num++] = 0x22; 844c65b1445SDouglas Gilbert arr[num++] = 0x20; 845c65b1445SDouglas Gilbert arr[num++] = (port_b >> 24); 846c65b1445SDouglas Gilbert arr[num++] = (port_b >> 16) & 0xff; 847c65b1445SDouglas Gilbert arr[num++] = (port_b >> 8) & 0xff; 848c65b1445SDouglas Gilbert arr[num++] = port_b & 0xff; 849c65b1445SDouglas Gilbert 850c65b1445SDouglas Gilbert return num; 851c65b1445SDouglas Gilbert } 852c65b1445SDouglas Gilbert 853c65b1445SDouglas Gilbert 854c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 855c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 856c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 857c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 858c65b1445SDouglas Gilbert '1','2','3','4', 859c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 860c65b1445SDouglas Gilbert 0xec,0,0,0, 861c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 862c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 863c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 864c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 865c65b1445SDouglas Gilbert 0x53,0x41, 866c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 867c65b1445SDouglas Gilbert 0x20,0x20, 868c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 869c65b1445SDouglas Gilbert 0x10,0x80, 870c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 871c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 872c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 873c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 874c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 875c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 876c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, 877c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 878c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 879c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 880c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 881c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 882c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 883c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, 884c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 885c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 886c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 887c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 888c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 889c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 890c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 891c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 892c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 893c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 894c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 895c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 896c65b1445SDouglas Gilbert }; 897c65b1445SDouglas Gilbert 898c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr) 899c65b1445SDouglas Gilbert { 900c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 901c65b1445SDouglas Gilbert return sizeof(vpd89_data); 902c65b1445SDouglas Gilbert } 903c65b1445SDouglas Gilbert 904c65b1445SDouglas Gilbert 905c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 906c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 907c65b1445SDouglas Gilbert 0,0,0x4,0, 908c65b1445SDouglas Gilbert 0,0,0,64, 909c65b1445SDouglas Gilbert }; 910c65b1445SDouglas Gilbert 911c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr) 912c65b1445SDouglas Gilbert { 913c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 914c65b1445SDouglas Gilbert if (sdebug_store_sectors > 0x400) { 915c65b1445SDouglas Gilbert arr[4] = (sdebug_store_sectors >> 24) & 0xff; 916c65b1445SDouglas Gilbert arr[5] = (sdebug_store_sectors >> 16) & 0xff; 917c65b1445SDouglas Gilbert arr[6] = (sdebug_store_sectors >> 8) & 0xff; 918c65b1445SDouglas Gilbert arr[7] = sdebug_store_sectors & 0xff; 919c65b1445SDouglas Gilbert } 920c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 9211da177e4SLinus Torvalds } 9221da177e4SLinus Torvalds 9231da177e4SLinus Torvalds 9241da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 925c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 9261da177e4SLinus Torvalds 9271da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd * scp, int target, 9281da177e4SLinus Torvalds struct sdebug_dev_info * devip) 9291da177e4SLinus Torvalds { 9301da177e4SLinus Torvalds unsigned char pq_pdt; 9311da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ]; 9321da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 933c65b1445SDouglas Gilbert int alloc_len, n; 9341da177e4SLinus Torvalds 9351da177e4SLinus Torvalds alloc_len = (cmd[3] << 8) + cmd[4]; 9361da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ); 937c65b1445SDouglas Gilbert if (devip->wlun) 938c65b1445SDouglas Gilbert pq_pdt = 0x1e; /* present, wlun */ 939c65b1445SDouglas Gilbert else if (scsi_debug_no_lun_0 && (0 == devip->lun)) 940c65b1445SDouglas Gilbert pq_pdt = 0x7f; /* not present, no device type */ 941c65b1445SDouglas Gilbert else 9421da177e4SLinus Torvalds pq_pdt = (scsi_debug_ptype & 0x1f); 9431da177e4SLinus Torvalds arr[0] = pq_pdt; 9441da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 9451da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 9461da177e4SLinus Torvalds 0); 9471da177e4SLinus Torvalds return check_condition_result; 9481da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 949c65b1445SDouglas Gilbert int lu_id_num, target_dev_id, len; 950c65b1445SDouglas Gilbert char lu_id_str[6]; 951c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 9521da177e4SLinus Torvalds 95323183910SDouglas Gilbert if (0 == scsi_debug_vpd_use_hostno) 95423183910SDouglas Gilbert host_no = 0; 955c65b1445SDouglas Gilbert lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) + 956c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 957c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 958c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 959c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 9601da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 961c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 962c65b1445SDouglas Gilbert n = 4; 963c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 964c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 965c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 966c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 967c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 968c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 969c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 970c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 971c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 972c65b1445SDouglas Gilbert arr[n++] = 0xb0; /* Block limits (SBC) */ 973c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 9741da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 975c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 9761da177e4SLinus Torvalds arr[3] = len; 977c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 9781da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 979c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 980c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_83(&arr[4], target_dev_id, 981c65b1445SDouglas Gilbert lu_id_num, lu_id_str, len); 982c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 983c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 984c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_84(&arr[4]); 985c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 986c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 987c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_85(&arr[4]); 988c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 989c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 990c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 991c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 992c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 993c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 994c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 995c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 996c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 997c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 998c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 999c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 1000c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 1001c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1002c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_88(&arr[4], target_dev_id); 1003c65b1445SDouglas Gilbert } else if (0x89 == cmd[2]) { /* ATA information */ 1004c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1005c65b1445SDouglas Gilbert n = inquiry_evpd_89(&arr[4]); 1006c65b1445SDouglas Gilbert arr[2] = (n >> 8); 1007c65b1445SDouglas Gilbert arr[3] = (n & 0xff); 1008c65b1445SDouglas Gilbert } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */ 1009c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1010c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_b0(&arr[4]); 10111da177e4SLinus Torvalds } else { 10121da177e4SLinus Torvalds /* Illegal request, invalid field in cdb */ 10131da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, 10141da177e4SLinus Torvalds INVALID_FIELD_IN_CDB, 0); 10151da177e4SLinus Torvalds return check_condition_result; 10161da177e4SLinus Torvalds } 1017c65b1445SDouglas Gilbert len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); 10181da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, 1019c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 10201da177e4SLinus Torvalds } 10211da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 10221da177e4SLinus Torvalds arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ 10231da177e4SLinus Torvalds arr[2] = scsi_debug_scsi_level; 10241da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 10251da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 1026c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 10271da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 1028c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 10291da177e4SLinus Torvalds memcpy(&arr[8], inq_vendor_id, 8); 10301da177e4SLinus Torvalds memcpy(&arr[16], inq_product_id, 16); 10311da177e4SLinus Torvalds memcpy(&arr[32], inq_product_rev, 4); 10321da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 1033c65b1445SDouglas Gilbert arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */ 1034c65b1445SDouglas Gilbert arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */ 1035c65b1445SDouglas Gilbert n = 62; 10361da177e4SLinus Torvalds if (scsi_debug_ptype == 0) { 1037c65b1445SDouglas Gilbert arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */ 10381da177e4SLinus Torvalds } else if (scsi_debug_ptype == 1) { 1039c65b1445SDouglas Gilbert arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */ 10401da177e4SLinus Torvalds } 1041c65b1445SDouglas Gilbert arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */ 10421da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, 10431da177e4SLinus Torvalds min(alloc_len, SDEBUG_LONG_INQ_SZ)); 10441da177e4SLinus Torvalds } 10451da177e4SLinus Torvalds 10461da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp, 10471da177e4SLinus Torvalds struct sdebug_dev_info * devip) 10481da177e4SLinus Torvalds { 10491da177e4SLinus Torvalds unsigned char * sbuff; 10501da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 10511da177e4SLinus Torvalds unsigned char arr[SDEBUG_SENSE_LEN]; 1052c65b1445SDouglas Gilbert int want_dsense; 10531da177e4SLinus Torvalds int len = 18; 10541da177e4SLinus Torvalds 1055c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 10561da177e4SLinus Torvalds if (devip->reset == 1) 1057c65b1445SDouglas Gilbert mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); 1058c65b1445SDouglas Gilbert want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense; 10591da177e4SLinus Torvalds sbuff = devip->sense_buff; 1060c65b1445SDouglas Gilbert if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 1061c65b1445SDouglas Gilbert if (want_dsense) { 1062c65b1445SDouglas Gilbert arr[0] = 0x72; 1063c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 1064c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 1065c65b1445SDouglas Gilbert arr[3] = 0xff; /* TEST set and MRIE==6 */ 1066c65b1445SDouglas Gilbert } else { 1067c65b1445SDouglas Gilbert arr[0] = 0x70; 1068c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 1069c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 1070c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 1071c65b1445SDouglas Gilbert arr[13] = 0xff; /* TEST set and MRIE==6 */ 1072c65b1445SDouglas Gilbert } 1073c65b1445SDouglas Gilbert } else { 1074c65b1445SDouglas Gilbert memcpy(arr, sbuff, SDEBUG_SENSE_LEN); 10751da177e4SLinus Torvalds if ((cmd[1] & 1) && (! scsi_debug_dsense)) { 10761da177e4SLinus Torvalds /* DESC bit set and sense_buff in fixed format */ 1077c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 10781da177e4SLinus Torvalds arr[0] = 0x72; 10791da177e4SLinus Torvalds arr[1] = sbuff[2]; /* sense key */ 10801da177e4SLinus Torvalds arr[2] = sbuff[12]; /* asc */ 10811da177e4SLinus Torvalds arr[3] = sbuff[13]; /* ascq */ 10821da177e4SLinus Torvalds len = 8; 1083c65b1445SDouglas Gilbert } 1084c65b1445SDouglas Gilbert } 1085c65b1445SDouglas Gilbert mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); 10861da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, len); 10871da177e4SLinus Torvalds } 10881da177e4SLinus Torvalds 1089c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp, 1090c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1091c65b1445SDouglas Gilbert { 1092c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1093c65b1445SDouglas Gilbert int power_cond, errsts, start; 1094c65b1445SDouglas Gilbert 1095c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1096c65b1445SDouglas Gilbert return errsts; 1097c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 1098c65b1445SDouglas Gilbert if (power_cond) { 1099c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 1100c65b1445SDouglas Gilbert 0); 1101c65b1445SDouglas Gilbert return check_condition_result; 1102c65b1445SDouglas Gilbert } 1103c65b1445SDouglas Gilbert start = cmd[4] & 1; 1104c65b1445SDouglas Gilbert if (start == devip->stopped) 1105c65b1445SDouglas Gilbert devip->stopped = !start; 1106c65b1445SDouglas Gilbert return 0; 1107c65b1445SDouglas Gilbert } 1108c65b1445SDouglas Gilbert 11091da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 11101da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp, 11111da177e4SLinus Torvalds struct sdebug_dev_info * devip) 11121da177e4SLinus Torvalds { 11131da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 1114c65b1445SDouglas Gilbert unsigned int capac; 11151da177e4SLinus Torvalds int errsts; 11161da177e4SLinus Torvalds 1117c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 11181da177e4SLinus Torvalds return errsts; 1119c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 1120c65b1445SDouglas Gilbert if (scsi_debug_virtual_gb > 0) { 1121c65b1445SDouglas Gilbert sdebug_capacity = 2048 * 1024; 1122c65b1445SDouglas Gilbert sdebug_capacity *= scsi_debug_virtual_gb; 1123c65b1445SDouglas Gilbert } else 1124c65b1445SDouglas Gilbert sdebug_capacity = sdebug_store_sectors; 11251da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 1126c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 1127c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 11281da177e4SLinus Torvalds arr[0] = (capac >> 24); 11291da177e4SLinus Torvalds arr[1] = (capac >> 16) & 0xff; 11301da177e4SLinus Torvalds arr[2] = (capac >> 8) & 0xff; 11311da177e4SLinus Torvalds arr[3] = capac & 0xff; 1132c65b1445SDouglas Gilbert } else { 1133c65b1445SDouglas Gilbert arr[0] = 0xff; 1134c65b1445SDouglas Gilbert arr[1] = 0xff; 1135c65b1445SDouglas Gilbert arr[2] = 0xff; 1136c65b1445SDouglas Gilbert arr[3] = 0xff; 1137c65b1445SDouglas Gilbert } 11381da177e4SLinus Torvalds arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; 11391da177e4SLinus Torvalds arr[7] = SECT_SIZE_PER(target) & 0xff; 11401da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 11411da177e4SLinus Torvalds } 11421da177e4SLinus Torvalds 1143c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 1144c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp, 1145c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1146c65b1445SDouglas Gilbert { 1147c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1148c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 1149c65b1445SDouglas Gilbert unsigned long long capac; 1150c65b1445SDouglas Gilbert int errsts, k, alloc_len; 1151c65b1445SDouglas Gilbert 1152c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1153c65b1445SDouglas Gilbert return errsts; 1154c65b1445SDouglas Gilbert alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8) 1155c65b1445SDouglas Gilbert + cmd[13]); 1156c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 1157c65b1445SDouglas Gilbert if (scsi_debug_virtual_gb > 0) { 1158c65b1445SDouglas Gilbert sdebug_capacity = 2048 * 1024; 1159c65b1445SDouglas Gilbert sdebug_capacity *= scsi_debug_virtual_gb; 1160c65b1445SDouglas Gilbert } else 1161c65b1445SDouglas Gilbert sdebug_capacity = sdebug_store_sectors; 1162c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 1163c65b1445SDouglas Gilbert capac = sdebug_capacity - 1; 1164c65b1445SDouglas Gilbert for (k = 0; k < 8; ++k, capac >>= 8) 1165c65b1445SDouglas Gilbert arr[7 - k] = capac & 0xff; 1166c65b1445SDouglas Gilbert arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff; 1167c65b1445SDouglas Gilbert arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff; 1168c65b1445SDouglas Gilbert arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff; 1169c65b1445SDouglas Gilbert arr[11] = SECT_SIZE_PER(target) & 0xff; 1170c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 1171c65b1445SDouglas Gilbert min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1172c65b1445SDouglas Gilbert } 1173c65b1445SDouglas Gilbert 11741da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 11751da177e4SLinus Torvalds 11761da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) 11771da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 11781da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 11791da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 11801da177e4SLinus Torvalds 11811da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 11821da177e4SLinus Torvalds if (1 == pcontrol) 11831da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 11841da177e4SLinus Torvalds return sizeof(err_recov_pg); 11851da177e4SLinus Torvalds } 11861da177e4SLinus Torvalds 11871da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) 11881da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 11891da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 11901da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 11911da177e4SLinus Torvalds 11921da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 11931da177e4SLinus Torvalds if (1 == pcontrol) 11941da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 11951da177e4SLinus Torvalds return sizeof(disconnect_pg); 11961da177e4SLinus Torvalds } 11971da177e4SLinus Torvalds 11981da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target) 11991da177e4SLinus Torvalds { /* Format device page for mode_sense */ 12001da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 12011da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 12021da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 12031da177e4SLinus Torvalds 12041da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 12051da177e4SLinus Torvalds p[10] = (sdebug_sectors_per >> 8) & 0xff; 12061da177e4SLinus Torvalds p[11] = sdebug_sectors_per & 0xff; 12071da177e4SLinus Torvalds p[12] = (SECT_SIZE >> 8) & 0xff; 12081da177e4SLinus Torvalds p[13] = SECT_SIZE & 0xff; 12091da177e4SLinus Torvalds if (DEV_REMOVEABLE(target)) 12101da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 12111da177e4SLinus Torvalds if (1 == pcontrol) 12121da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 12131da177e4SLinus Torvalds return sizeof(format_pg); 12141da177e4SLinus Torvalds } 12151da177e4SLinus Torvalds 12161da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target) 12171da177e4SLinus Torvalds { /* Caching page for mode_sense */ 12181da177e4SLinus Torvalds unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 12191da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 12201da177e4SLinus Torvalds 12211da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 12221da177e4SLinus Torvalds if (1 == pcontrol) 12231da177e4SLinus Torvalds memset(p + 2, 0, sizeof(caching_pg) - 2); 12241da177e4SLinus Torvalds return sizeof(caching_pg); 12251da177e4SLinus Torvalds } 12261da177e4SLinus Torvalds 12271da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) 12281da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 1229c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 1230c65b1445SDouglas Gilbert 0, 0, 0, 0}; 1231c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 12321da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 12331da177e4SLinus Torvalds 12341da177e4SLinus Torvalds if (scsi_debug_dsense) 12351da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 1236c65b1445SDouglas Gilbert else 1237c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 12381da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 12391da177e4SLinus Torvalds if (1 == pcontrol) 1240c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 1241c65b1445SDouglas Gilbert else if (2 == pcontrol) 1242c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 12431da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 12441da177e4SLinus Torvalds } 12451da177e4SLinus Torvalds 1246c65b1445SDouglas Gilbert 12471da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) 12481da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 1249c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 12501da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 1251c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1252c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 1253c65b1445SDouglas Gilbert 12541da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 12551da177e4SLinus Torvalds if (1 == pcontrol) 1256c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 1257c65b1445SDouglas Gilbert else if (2 == pcontrol) 1258c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 12591da177e4SLinus Torvalds return sizeof(iec_m_pg); 12601da177e4SLinus Torvalds } 12611da177e4SLinus Torvalds 1262c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target) 1263c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 1264c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 1265c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 1266c65b1445SDouglas Gilbert 1267c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 1268c65b1445SDouglas Gilbert if (1 == pcontrol) 1269c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 1270c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 1271c65b1445SDouglas Gilbert } 1272c65b1445SDouglas Gilbert 1273c65b1445SDouglas Gilbert 1274c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, 1275c65b1445SDouglas Gilbert int target_dev_id) 1276c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 1277c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 1278c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 1279c65b1445SDouglas Gilbert 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, 1280c65b1445SDouglas Gilbert 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, 1281c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 1282c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1283c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1284c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 1285c65b1445SDouglas Gilbert 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, 1286c65b1445SDouglas Gilbert 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, 1287c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 1288c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1289c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1290c65b1445SDouglas Gilbert }; 1291c65b1445SDouglas Gilbert int port_a, port_b; 1292c65b1445SDouglas Gilbert 1293c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1294c65b1445SDouglas Gilbert port_b = port_a + 1; 1295c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 1296c65b1445SDouglas Gilbert p[20] = (port_a >> 24); 1297c65b1445SDouglas Gilbert p[21] = (port_a >> 16) & 0xff; 1298c65b1445SDouglas Gilbert p[22] = (port_a >> 8) & 0xff; 1299c65b1445SDouglas Gilbert p[23] = port_a & 0xff; 1300c65b1445SDouglas Gilbert p[48 + 20] = (port_b >> 24); 1301c65b1445SDouglas Gilbert p[48 + 21] = (port_b >> 16) & 0xff; 1302c65b1445SDouglas Gilbert p[48 + 22] = (port_b >> 8) & 0xff; 1303c65b1445SDouglas Gilbert p[48 + 23] = port_b & 0xff; 1304c65b1445SDouglas Gilbert if (1 == pcontrol) 1305c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 1306c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 1307c65b1445SDouglas Gilbert } 1308c65b1445SDouglas Gilbert 1309c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) 1310c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 1311c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 1312c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1313c65b1445SDouglas Gilbert }; 1314c65b1445SDouglas Gilbert 1315c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 1316c65b1445SDouglas Gilbert if (1 == pcontrol) 1317c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 1318c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 1319c65b1445SDouglas Gilbert } 1320c65b1445SDouglas Gilbert 13211da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 13221da177e4SLinus Torvalds 13231da177e4SLinus Torvalds static int resp_mode_sense(struct scsi_cmnd * scp, int target, 13241da177e4SLinus Torvalds struct sdebug_dev_info * devip) 13251da177e4SLinus Torvalds { 132623183910SDouglas Gilbert unsigned char dbd, llbaa; 132723183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 13281da177e4SLinus Torvalds unsigned char dev_spec; 132923183910SDouglas Gilbert int k, alloc_len, msense_6, offset, len, errsts, target_dev_id; 13301da177e4SLinus Torvalds unsigned char * ap; 13311da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 13321da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 13331da177e4SLinus Torvalds 1334c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 13351da177e4SLinus Torvalds return errsts; 133623183910SDouglas Gilbert dbd = !!(cmd[1] & 0x8); 13371da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 13381da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 13391da177e4SLinus Torvalds subpcode = cmd[3]; 13401da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 134123183910SDouglas Gilbert llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10); 134223183910SDouglas Gilbert if ((0 == scsi_debug_ptype) && (0 == dbd)) 134323183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 134423183910SDouglas Gilbert else 134523183910SDouglas Gilbert bd_len = 0; 13461da177e4SLinus Torvalds alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]); 13471da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 13481da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 13491da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 13501da177e4SLinus Torvalds 0); 13511da177e4SLinus Torvalds return check_condition_result; 13521da177e4SLinus Torvalds } 1353c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 1354c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 135523183910SDouglas Gilbert /* set DPOFUA bit for disks */ 135623183910SDouglas Gilbert if (0 == scsi_debug_ptype) 135723183910SDouglas Gilbert dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10; 135823183910SDouglas Gilbert else 135923183910SDouglas Gilbert dev_spec = 0x0; 13601da177e4SLinus Torvalds if (msense_6) { 13611da177e4SLinus Torvalds arr[2] = dev_spec; 136223183910SDouglas Gilbert arr[3] = bd_len; 13631da177e4SLinus Torvalds offset = 4; 13641da177e4SLinus Torvalds } else { 13651da177e4SLinus Torvalds arr[3] = dev_spec; 136623183910SDouglas Gilbert if (16 == bd_len) 136723183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 136823183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 13691da177e4SLinus Torvalds offset = 8; 13701da177e4SLinus Torvalds } 13711da177e4SLinus Torvalds ap = arr + offset; 137223183910SDouglas Gilbert if ((bd_len > 0) && (0 == sdebug_capacity)) { 137323183910SDouglas Gilbert if (scsi_debug_virtual_gb > 0) { 137423183910SDouglas Gilbert sdebug_capacity = 2048 * 1024; 137523183910SDouglas Gilbert sdebug_capacity *= scsi_debug_virtual_gb; 137623183910SDouglas Gilbert } else 137723183910SDouglas Gilbert sdebug_capacity = sdebug_store_sectors; 137823183910SDouglas Gilbert } 137923183910SDouglas Gilbert if (8 == bd_len) { 138023183910SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) { 138123183910SDouglas Gilbert ap[0] = 0xff; 138223183910SDouglas Gilbert ap[1] = 0xff; 138323183910SDouglas Gilbert ap[2] = 0xff; 138423183910SDouglas Gilbert ap[3] = 0xff; 138523183910SDouglas Gilbert } else { 138623183910SDouglas Gilbert ap[0] = (sdebug_capacity >> 24) & 0xff; 138723183910SDouglas Gilbert ap[1] = (sdebug_capacity >> 16) & 0xff; 138823183910SDouglas Gilbert ap[2] = (sdebug_capacity >> 8) & 0xff; 138923183910SDouglas Gilbert ap[3] = sdebug_capacity & 0xff; 139023183910SDouglas Gilbert } 139123183910SDouglas Gilbert ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; 139223183910SDouglas Gilbert ap[7] = SECT_SIZE_PER(target) & 0xff; 139323183910SDouglas Gilbert offset += bd_len; 139423183910SDouglas Gilbert ap = arr + offset; 139523183910SDouglas Gilbert } else if (16 == bd_len) { 139623183910SDouglas Gilbert unsigned long long capac = sdebug_capacity; 139723183910SDouglas Gilbert 139823183910SDouglas Gilbert for (k = 0; k < 8; ++k, capac >>= 8) 139923183910SDouglas Gilbert ap[7 - k] = capac & 0xff; 140023183910SDouglas Gilbert ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff; 140123183910SDouglas Gilbert ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff; 140223183910SDouglas Gilbert ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff; 140323183910SDouglas Gilbert ap[15] = SECT_SIZE_PER(target) & 0xff; 140423183910SDouglas Gilbert offset += bd_len; 140523183910SDouglas Gilbert ap = arr + offset; 140623183910SDouglas Gilbert } 14071da177e4SLinus Torvalds 1408c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 1409c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 14101da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 14111da177e4SLinus Torvalds 0); 14121da177e4SLinus Torvalds return check_condition_result; 14131da177e4SLinus Torvalds } 14141da177e4SLinus Torvalds switch (pcode) { 14151da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 14161da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 14171da177e4SLinus Torvalds offset += len; 14181da177e4SLinus Torvalds break; 14191da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 14201da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 14211da177e4SLinus Torvalds offset += len; 14221da177e4SLinus Torvalds break; 14231da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 14241da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 14251da177e4SLinus Torvalds offset += len; 14261da177e4SLinus Torvalds break; 14271da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 14281da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 14291da177e4SLinus Torvalds offset += len; 14301da177e4SLinus Torvalds break; 14311da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 14321da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 14331da177e4SLinus Torvalds offset += len; 14341da177e4SLinus Torvalds break; 1435c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 1436c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 1437c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1438c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1439c65b1445SDouglas Gilbert return check_condition_result; 1440c65b1445SDouglas Gilbert } 1441c65b1445SDouglas Gilbert len = 0; 1442c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 1443c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 1444c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 1445c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 1446c65b1445SDouglas Gilbert target_dev_id); 1447c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 1448c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 1449c65b1445SDouglas Gilbert offset += len; 1450c65b1445SDouglas Gilbert break; 14511da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 14521da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 14531da177e4SLinus Torvalds offset += len; 14541da177e4SLinus Torvalds break; 14551da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 1456c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 14571da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 14581da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 14591da177e4SLinus Torvalds len += resp_format_pg(ap + len, pcontrol, target); 14601da177e4SLinus Torvalds len += resp_caching_pg(ap + len, pcontrol, target); 14611da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 1462c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 1463c65b1445SDouglas Gilbert if (0xff == subpcode) { 1464c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 1465c65b1445SDouglas Gilbert target, target_dev_id); 1466c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 1467c65b1445SDouglas Gilbert } 14681da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 1469c65b1445SDouglas Gilbert } else { 1470c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1471c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1472c65b1445SDouglas Gilbert return check_condition_result; 1473c65b1445SDouglas Gilbert } 14741da177e4SLinus Torvalds offset += len; 14751da177e4SLinus Torvalds break; 14761da177e4SLinus Torvalds default: 14771da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 14781da177e4SLinus Torvalds 0); 14791da177e4SLinus Torvalds return check_condition_result; 14801da177e4SLinus Torvalds } 14811da177e4SLinus Torvalds if (msense_6) 14821da177e4SLinus Torvalds arr[0] = offset - 1; 14831da177e4SLinus Torvalds else { 14841da177e4SLinus Torvalds arr[0] = ((offset - 2) >> 8) & 0xff; 14851da177e4SLinus Torvalds arr[1] = (offset - 2) & 0xff; 14861da177e4SLinus Torvalds } 14871da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); 14881da177e4SLinus Torvalds } 14891da177e4SLinus Torvalds 1490c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 1491c65b1445SDouglas Gilbert 1492c65b1445SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd * scp, int mselect6, 1493c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1494c65b1445SDouglas Gilbert { 1495c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 1496c65b1445SDouglas Gilbert int param_len, res, errsts, mpage; 1497c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 1498c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1499c65b1445SDouglas Gilbert 1500c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1501c65b1445SDouglas Gilbert return errsts; 1502c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1503c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 1504c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 1505c65b1445SDouglas Gilbert param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]); 1506c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 1507c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1508c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1509c65b1445SDouglas Gilbert return check_condition_result; 1510c65b1445SDouglas Gilbert } 1511c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 1512c65b1445SDouglas Gilbert if (-1 == res) 1513c65b1445SDouglas Gilbert return (DID_ERROR << 16); 1514c65b1445SDouglas Gilbert else if ((res < param_len) && 1515c65b1445SDouglas Gilbert (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 1516c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, " 1517c65b1445SDouglas Gilbert " IO sent=%d bytes\n", param_len, res); 1518c65b1445SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2); 1519c65b1445SDouglas Gilbert bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]); 152023183910SDouglas Gilbert if (md_len > 2) { 1521c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1522c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1523c65b1445SDouglas Gilbert return check_condition_result; 1524c65b1445SDouglas Gilbert } 1525c65b1445SDouglas Gilbert off = bd_len + (mselect6 ? 4 : 8); 1526c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 1527c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 1528c65b1445SDouglas Gilbert if (ps) { 1529c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1530c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1531c65b1445SDouglas Gilbert return check_condition_result; 1532c65b1445SDouglas Gilbert } 1533c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 1534c65b1445SDouglas Gilbert pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) : 1535c65b1445SDouglas Gilbert (arr[off + 1] + 2); 1536c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 1537c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1538c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 1539c65b1445SDouglas Gilbert return check_condition_result; 1540c65b1445SDouglas Gilbert } 1541c65b1445SDouglas Gilbert switch (mpage) { 1542c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 1543c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 1544c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 1545c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 1546c65b1445SDouglas Gilbert scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4); 1547c65b1445SDouglas Gilbert return 0; 1548c65b1445SDouglas Gilbert } 1549c65b1445SDouglas Gilbert break; 1550c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 1551c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 1552c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 1553c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 1554c65b1445SDouglas Gilbert return 0; 1555c65b1445SDouglas Gilbert } 1556c65b1445SDouglas Gilbert break; 1557c65b1445SDouglas Gilbert default: 1558c65b1445SDouglas Gilbert break; 1559c65b1445SDouglas Gilbert } 1560c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1561c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1562c65b1445SDouglas Gilbert return check_condition_result; 1563c65b1445SDouglas Gilbert } 1564c65b1445SDouglas Gilbert 1565c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr) 1566c65b1445SDouglas Gilbert { 1567c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 1568c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 1569c65b1445SDouglas Gilbert }; 1570c65b1445SDouglas Gilbert 1571c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 1572c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 1573c65b1445SDouglas Gilbert } 1574c65b1445SDouglas Gilbert 1575c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr) 1576c65b1445SDouglas Gilbert { 1577c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 1578c65b1445SDouglas Gilbert }; 1579c65b1445SDouglas Gilbert 1580c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 1581c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 1582c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 1583c65b1445SDouglas Gilbert arr[5] = 0xff; 1584c65b1445SDouglas Gilbert } 1585c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 1586c65b1445SDouglas Gilbert } 1587c65b1445SDouglas Gilbert 1588c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 1589c65b1445SDouglas Gilbert 1590c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp, 1591c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1592c65b1445SDouglas Gilbert { 159323183910SDouglas Gilbert int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n; 1594c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 1595c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1596c65b1445SDouglas Gilbert 1597c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1598c65b1445SDouglas Gilbert return errsts; 1599c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1600c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 1601c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 1602c65b1445SDouglas Gilbert if (ppc || sp) { 1603c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1604c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1605c65b1445SDouglas Gilbert return check_condition_result; 1606c65b1445SDouglas Gilbert } 1607c65b1445SDouglas Gilbert pcontrol = (cmd[2] & 0xc0) >> 6; 1608c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 160923183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 1610c65b1445SDouglas Gilbert alloc_len = (cmd[7] << 8) + cmd[8]; 1611c65b1445SDouglas Gilbert arr[0] = pcode; 161223183910SDouglas Gilbert if (0 == subpcode) { 1613c65b1445SDouglas Gilbert switch (pcode) { 1614c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 1615c65b1445SDouglas Gilbert n = 4; 1616c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1617c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 1618c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 1619c65b1445SDouglas Gilbert arr[3] = n - 4; 1620c65b1445SDouglas Gilbert break; 1621c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 1622c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 1623c65b1445SDouglas Gilbert break; 1624c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 1625c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 1626c65b1445SDouglas Gilbert break; 1627c65b1445SDouglas Gilbert default: 1628c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1629c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1630c65b1445SDouglas Gilbert return check_condition_result; 1631c65b1445SDouglas Gilbert } 163223183910SDouglas Gilbert } else if (0xff == subpcode) { 163323183910SDouglas Gilbert arr[0] |= 0x40; 163423183910SDouglas Gilbert arr[1] = subpcode; 163523183910SDouglas Gilbert switch (pcode) { 163623183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 163723183910SDouglas Gilbert n = 4; 163823183910SDouglas Gilbert arr[n++] = 0x0; 163923183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 164023183910SDouglas Gilbert arr[n++] = 0x0; 164123183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 164223183910SDouglas Gilbert arr[n++] = 0xd; 164323183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 164423183910SDouglas Gilbert arr[n++] = 0x2f; 164523183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 164623183910SDouglas Gilbert arr[3] = n - 4; 164723183910SDouglas Gilbert break; 164823183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 164923183910SDouglas Gilbert n = 4; 165023183910SDouglas Gilbert arr[n++] = 0xd; 165123183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 165223183910SDouglas Gilbert arr[3] = n - 4; 165323183910SDouglas Gilbert break; 165423183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 165523183910SDouglas Gilbert n = 4; 165623183910SDouglas Gilbert arr[n++] = 0x2f; 165723183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 165823183910SDouglas Gilbert arr[3] = n - 4; 165923183910SDouglas Gilbert break; 166023183910SDouglas Gilbert default: 166123183910SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 166223183910SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 166323183910SDouglas Gilbert return check_condition_result; 166423183910SDouglas Gilbert } 166523183910SDouglas Gilbert } else { 166623183910SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 166723183910SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 166823183910SDouglas Gilbert return check_condition_result; 166923183910SDouglas Gilbert } 1670c65b1445SDouglas Gilbert len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); 1671c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 1672c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 1673c65b1445SDouglas Gilbert } 1674c65b1445SDouglas Gilbert 1675c65b1445SDouglas Gilbert static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba, 1676c65b1445SDouglas Gilbert unsigned int num, struct sdebug_dev_info * devip) 16771da177e4SLinus Torvalds { 16781da177e4SLinus Torvalds unsigned long iflags; 1679c65b1445SDouglas Gilbert unsigned int block, from_bottom; 1680c65b1445SDouglas Gilbert unsigned long long u; 16811da177e4SLinus Torvalds int ret; 16821da177e4SLinus Torvalds 1683c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 16841da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 16851da177e4SLinus Torvalds 0); 16861da177e4SLinus Torvalds return check_condition_result; 16871da177e4SLinus Torvalds } 1688c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 1689c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 1690c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 1691c65b1445SDouglas Gilbert 0); 1692c65b1445SDouglas Gilbert return check_condition_result; 1693c65b1445SDouglas Gilbert } 16941da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && 1695c65b1445SDouglas Gilbert (lba <= OPT_MEDIUM_ERR_ADDR) && 1696c65b1445SDouglas Gilbert ((lba + num) > OPT_MEDIUM_ERR_ADDR)) { 1697c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 16981da177e4SLinus Torvalds mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 16991da177e4SLinus Torvalds 0); 1700c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 1701c65b1445SDouglas Gilbert if (0x70 == (devip->sense_buff[0] & 0x7f)) { 1702c65b1445SDouglas Gilbert devip->sense_buff[0] |= 0x80; /* Valid bit */ 1703c65b1445SDouglas Gilbert ret = OPT_MEDIUM_ERR_ADDR; 1704c65b1445SDouglas Gilbert devip->sense_buff[3] = (ret >> 24) & 0xff; 1705c65b1445SDouglas Gilbert devip->sense_buff[4] = (ret >> 16) & 0xff; 1706c65b1445SDouglas Gilbert devip->sense_buff[5] = (ret >> 8) & 0xff; 1707c65b1445SDouglas Gilbert devip->sense_buff[6] = ret & 0xff; 1708c65b1445SDouglas Gilbert } 17091da177e4SLinus Torvalds return check_condition_result; 17101da177e4SLinus Torvalds } 17111da177e4SLinus Torvalds read_lock_irqsave(&atomic_rw, iflags); 1712c65b1445SDouglas Gilbert if ((lba + num) <= sdebug_store_sectors) 1713c65b1445SDouglas Gilbert ret = fill_from_dev_buffer(SCpnt, 1714c65b1445SDouglas Gilbert fake_storep + (lba * SECT_SIZE), 17151da177e4SLinus Torvalds num * SECT_SIZE); 1716c65b1445SDouglas Gilbert else { 1717c65b1445SDouglas Gilbert /* modulo when one arg is 64 bits needs do_div() */ 1718c65b1445SDouglas Gilbert u = lba; 1719c65b1445SDouglas Gilbert block = do_div(u, sdebug_store_sectors); 1720c65b1445SDouglas Gilbert from_bottom = 0; 1721c65b1445SDouglas Gilbert if ((block + num) > sdebug_store_sectors) 1722c65b1445SDouglas Gilbert from_bottom = (block + num) - sdebug_store_sectors; 1723c65b1445SDouglas Gilbert ret = fill_from_dev_buffer(SCpnt, 1724c65b1445SDouglas Gilbert fake_storep + (block * SECT_SIZE), 1725c65b1445SDouglas Gilbert (num - from_bottom) * SECT_SIZE); 1726c65b1445SDouglas Gilbert if ((0 == ret) && (from_bottom > 0)) 1727c65b1445SDouglas Gilbert ret = fill_from_dev_buffer(SCpnt, fake_storep, 1728c65b1445SDouglas Gilbert from_bottom * SECT_SIZE); 1729c65b1445SDouglas Gilbert } 17301da177e4SLinus Torvalds read_unlock_irqrestore(&atomic_rw, iflags); 17311da177e4SLinus Torvalds return ret; 17321da177e4SLinus Torvalds } 17331da177e4SLinus Torvalds 1734c65b1445SDouglas Gilbert static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba, 1735c65b1445SDouglas Gilbert unsigned int num, struct sdebug_dev_info * devip) 17361da177e4SLinus Torvalds { 17371da177e4SLinus Torvalds unsigned long iflags; 1738c65b1445SDouglas Gilbert unsigned int block, to_bottom; 1739c65b1445SDouglas Gilbert unsigned long long u; 17401da177e4SLinus Torvalds int res; 17411da177e4SLinus Torvalds 1742c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 17431da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 17441da177e4SLinus Torvalds 0); 17451da177e4SLinus Torvalds return check_condition_result; 17461da177e4SLinus Torvalds } 1747c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 1748c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 1749c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 1750c65b1445SDouglas Gilbert 0); 1751c65b1445SDouglas Gilbert return check_condition_result; 1752c65b1445SDouglas Gilbert } 17531da177e4SLinus Torvalds 17541da177e4SLinus Torvalds write_lock_irqsave(&atomic_rw, iflags); 1755c65b1445SDouglas Gilbert if ((lba + num) <= sdebug_store_sectors) 1756c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(SCpnt, 1757c65b1445SDouglas Gilbert fake_storep + (lba * SECT_SIZE), 17581da177e4SLinus Torvalds num * SECT_SIZE); 1759c65b1445SDouglas Gilbert else { 1760c65b1445SDouglas Gilbert /* modulo when one arg is 64 bits needs do_div() */ 1761c65b1445SDouglas Gilbert u = lba; 1762c65b1445SDouglas Gilbert block = do_div(u, sdebug_store_sectors); 1763c65b1445SDouglas Gilbert to_bottom = 0; 1764c65b1445SDouglas Gilbert if ((block + num) > sdebug_store_sectors) 1765c65b1445SDouglas Gilbert to_bottom = (block + num) - sdebug_store_sectors; 1766c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(SCpnt, 1767c65b1445SDouglas Gilbert fake_storep + (block * SECT_SIZE), 1768c65b1445SDouglas Gilbert (num - to_bottom) * SECT_SIZE); 1769c65b1445SDouglas Gilbert if ((0 == res) && (to_bottom > 0)) 1770c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(SCpnt, fake_storep, 1771c65b1445SDouglas Gilbert to_bottom * SECT_SIZE); 1772c65b1445SDouglas Gilbert } 17731da177e4SLinus Torvalds write_unlock_irqrestore(&atomic_rw, iflags); 17741da177e4SLinus Torvalds if (-1 == res) 17751da177e4SLinus Torvalds return (DID_ERROR << 16); 17761da177e4SLinus Torvalds else if ((res < (num * SECT_SIZE)) && 17771da177e4SLinus Torvalds (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 1778c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " 17791da177e4SLinus Torvalds " IO sent=%d bytes\n", num * SECT_SIZE, res); 17801da177e4SLinus Torvalds return 0; 17811da177e4SLinus Torvalds } 17821da177e4SLinus Torvalds 1783c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256 17841da177e4SLinus Torvalds 17851da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp, 17861da177e4SLinus Torvalds struct sdebug_dev_info * devip) 17871da177e4SLinus Torvalds { 17881da177e4SLinus Torvalds unsigned int alloc_len; 1789c65b1445SDouglas Gilbert int lun_cnt, i, upper, num, n, wlun, lun; 17901da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 17911da177e4SLinus Torvalds int select_report = (int)cmd[2]; 17921da177e4SLinus Torvalds struct scsi_lun *one_lun; 17931da177e4SLinus Torvalds unsigned char arr[SDEBUG_RLUN_ARR_SZ]; 1794c65b1445SDouglas Gilbert unsigned char * max_addr; 17951da177e4SLinus Torvalds 17961da177e4SLinus Torvalds alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); 1797c65b1445SDouglas Gilbert if ((alloc_len < 4) || (select_report > 2)) { 17981da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 17991da177e4SLinus Torvalds 0); 18001da177e4SLinus Torvalds return check_condition_result; 18011da177e4SLinus Torvalds } 18021da177e4SLinus Torvalds /* can produce response with up to 16k luns (lun 0 to lun 16383) */ 18031da177e4SLinus Torvalds memset(arr, 0, SDEBUG_RLUN_ARR_SZ); 18041da177e4SLinus Torvalds lun_cnt = scsi_debug_max_luns; 1805c65b1445SDouglas Gilbert if (1 == select_report) 1806c65b1445SDouglas Gilbert lun_cnt = 0; 1807c65b1445SDouglas Gilbert else if (scsi_debug_no_lun_0 && (lun_cnt > 0)) 1808c65b1445SDouglas Gilbert --lun_cnt; 1809c65b1445SDouglas Gilbert wlun = (select_report > 0) ? 1 : 0; 1810c65b1445SDouglas Gilbert num = lun_cnt + wlun; 1811c65b1445SDouglas Gilbert arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff; 1812c65b1445SDouglas Gilbert arr[3] = (sizeof(struct scsi_lun) * num) & 0xff; 1813c65b1445SDouglas Gilbert n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) / 1814c65b1445SDouglas Gilbert sizeof(struct scsi_lun)), num); 1815c65b1445SDouglas Gilbert if (n < num) { 1816c65b1445SDouglas Gilbert wlun = 0; 1817c65b1445SDouglas Gilbert lun_cnt = n; 1818c65b1445SDouglas Gilbert } 18191da177e4SLinus Torvalds one_lun = (struct scsi_lun *) &arr[8]; 1820c65b1445SDouglas Gilbert max_addr = arr + SDEBUG_RLUN_ARR_SZ; 1821c65b1445SDouglas Gilbert for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0); 1822c65b1445SDouglas Gilbert ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr)); 1823c65b1445SDouglas Gilbert i++, lun++) { 1824c65b1445SDouglas Gilbert upper = (lun >> 8) & 0x3f; 18251da177e4SLinus Torvalds if (upper) 18261da177e4SLinus Torvalds one_lun[i].scsi_lun[0] = 18271da177e4SLinus Torvalds (upper | (SAM2_LUN_ADDRESS_METHOD << 6)); 1828c65b1445SDouglas Gilbert one_lun[i].scsi_lun[1] = lun & 0xff; 18291da177e4SLinus Torvalds } 1830c65b1445SDouglas Gilbert if (wlun) { 1831c65b1445SDouglas Gilbert one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff; 1832c65b1445SDouglas Gilbert one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff; 1833c65b1445SDouglas Gilbert i++; 1834c65b1445SDouglas Gilbert } 1835c65b1445SDouglas Gilbert alloc_len = (unsigned char *)(one_lun + i) - arr; 18361da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, 18371da177e4SLinus Torvalds min((int)alloc_len, SDEBUG_RLUN_ARR_SZ)); 18381da177e4SLinus Torvalds } 18391da177e4SLinus Torvalds 18401da177e4SLinus Torvalds /* When timer goes off this function is called. */ 18411da177e4SLinus Torvalds static void timer_intr_handler(unsigned long indx) 18421da177e4SLinus Torvalds { 18431da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 18441da177e4SLinus Torvalds unsigned long iflags; 18451da177e4SLinus Torvalds 18461da177e4SLinus Torvalds if (indx >= SCSI_DEBUG_CANQUEUE) { 18471da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too " 18481da177e4SLinus Torvalds "large\n"); 18491da177e4SLinus Torvalds return; 18501da177e4SLinus Torvalds } 18511da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 18521da177e4SLinus Torvalds sqcp = &queued_arr[(int)indx]; 18531da177e4SLinus Torvalds if (! sqcp->in_use) { 18541da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected " 18551da177e4SLinus Torvalds "interrupt\n"); 18561da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 18571da177e4SLinus Torvalds return; 18581da177e4SLinus Torvalds } 18591da177e4SLinus Torvalds sqcp->in_use = 0; 18601da177e4SLinus Torvalds if (sqcp->done_funct) { 18611da177e4SLinus Torvalds sqcp->a_cmnd->result = sqcp->scsi_result; 18621da177e4SLinus Torvalds sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */ 18631da177e4SLinus Torvalds } 18641da177e4SLinus Torvalds sqcp->done_funct = NULL; 18651da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 18661da177e4SLinus Torvalds } 18671da177e4SLinus Torvalds 18681da177e4SLinus Torvalds static int scsi_debug_slave_alloc(struct scsi_device * sdp) 18691da177e4SLinus Torvalds { 18701da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 1871c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n", 1872c65b1445SDouglas Gilbert sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 18731da177e4SLinus Torvalds return 0; 18741da177e4SLinus Torvalds } 18751da177e4SLinus Torvalds 18761da177e4SLinus Torvalds static int scsi_debug_slave_configure(struct scsi_device * sdp) 18771da177e4SLinus Torvalds { 18781da177e4SLinus Torvalds struct sdebug_dev_info * devip; 18791da177e4SLinus Torvalds 18801da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 1881c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n", 1882c65b1445SDouglas Gilbert sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 18831da177e4SLinus Torvalds if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) 18841da177e4SLinus Torvalds sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; 18851da177e4SLinus Torvalds devip = devInfoReg(sdp); 18861da177e4SLinus Torvalds sdp->hostdata = devip; 18871da177e4SLinus Torvalds if (sdp->host->cmd_per_lun) 18881da177e4SLinus Torvalds scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING, 18891da177e4SLinus Torvalds sdp->host->cmd_per_lun); 1890c65b1445SDouglas Gilbert blk_queue_max_segment_size(sdp->request_queue, 256 * 1024); 18911da177e4SLinus Torvalds return 0; 18921da177e4SLinus Torvalds } 18931da177e4SLinus Torvalds 18941da177e4SLinus Torvalds static void scsi_debug_slave_destroy(struct scsi_device * sdp) 18951da177e4SLinus Torvalds { 18961da177e4SLinus Torvalds struct sdebug_dev_info * devip = 18971da177e4SLinus Torvalds (struct sdebug_dev_info *)sdp->hostdata; 18981da177e4SLinus Torvalds 18991da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 1900c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n", 1901c65b1445SDouglas Gilbert sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 19021da177e4SLinus Torvalds if (devip) { 19031da177e4SLinus Torvalds /* make this slot avaliable for re-use */ 19041da177e4SLinus Torvalds devip->used = 0; 19051da177e4SLinus Torvalds sdp->hostdata = NULL; 19061da177e4SLinus Torvalds } 19071da177e4SLinus Torvalds } 19081da177e4SLinus Torvalds 19091da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) 19101da177e4SLinus Torvalds { 19111da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 19121da177e4SLinus Torvalds struct sdebug_dev_info * open_devip = NULL; 19131da177e4SLinus Torvalds struct sdebug_dev_info * devip = 19141da177e4SLinus Torvalds (struct sdebug_dev_info *)sdev->hostdata; 19151da177e4SLinus Torvalds 19161da177e4SLinus Torvalds if (devip) 19171da177e4SLinus Torvalds return devip; 19181da177e4SLinus Torvalds sdbg_host = *(struct sdebug_host_info **) sdev->host->hostdata; 19191da177e4SLinus Torvalds if(! sdbg_host) { 19201da177e4SLinus Torvalds printk(KERN_ERR "Host info NULL\n"); 19211da177e4SLinus Torvalds return NULL; 19221da177e4SLinus Torvalds } 19231da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 19241da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 19251da177e4SLinus Torvalds (devip->target == sdev->id) && 19261da177e4SLinus Torvalds (devip->lun == sdev->lun)) 19271da177e4SLinus Torvalds return devip; 19281da177e4SLinus Torvalds else { 19291da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 19301da177e4SLinus Torvalds open_devip = devip; 19311da177e4SLinus Torvalds } 19321da177e4SLinus Torvalds } 19331da177e4SLinus Torvalds if (NULL == open_devip) { /* try and make a new one */ 193424669f75SJes Sorensen open_devip = kzalloc(sizeof(*open_devip),GFP_KERNEL); 19351da177e4SLinus Torvalds if (NULL == open_devip) { 19361da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 19371da177e4SLinus Torvalds __FUNCTION__, __LINE__); 19381da177e4SLinus Torvalds return NULL; 19391da177e4SLinus Torvalds } 19401da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 19411da177e4SLinus Torvalds list_add_tail(&open_devip->dev_list, 19421da177e4SLinus Torvalds &sdbg_host->dev_info_list); 19431da177e4SLinus Torvalds } 19441da177e4SLinus Torvalds if (open_devip) { 19451da177e4SLinus Torvalds open_devip->channel = sdev->channel; 19461da177e4SLinus Torvalds open_devip->target = sdev->id; 19471da177e4SLinus Torvalds open_devip->lun = sdev->lun; 19481da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 19491da177e4SLinus Torvalds open_devip->reset = 1; 19501da177e4SLinus Torvalds open_devip->used = 1; 19511da177e4SLinus Torvalds memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN); 19521da177e4SLinus Torvalds if (scsi_debug_dsense) 19531da177e4SLinus Torvalds open_devip->sense_buff[0] = 0x72; 19541da177e4SLinus Torvalds else { 19551da177e4SLinus Torvalds open_devip->sense_buff[0] = 0x70; 19561da177e4SLinus Torvalds open_devip->sense_buff[7] = 0xa; 19571da177e4SLinus Torvalds } 1958c65b1445SDouglas Gilbert if (sdev->lun == SAM2_WLUN_REPORT_LUNS) 1959c65b1445SDouglas Gilbert open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff; 19601da177e4SLinus Torvalds return open_devip; 19611da177e4SLinus Torvalds } 19621da177e4SLinus Torvalds return NULL; 19631da177e4SLinus Torvalds } 19641da177e4SLinus Torvalds 19651da177e4SLinus Torvalds static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, 19661da177e4SLinus Torvalds int asc, int asq) 19671da177e4SLinus Torvalds { 19681da177e4SLinus Torvalds unsigned char * sbuff; 19691da177e4SLinus Torvalds 19701da177e4SLinus Torvalds sbuff = devip->sense_buff; 19711da177e4SLinus Torvalds memset(sbuff, 0, SDEBUG_SENSE_LEN); 19721da177e4SLinus Torvalds if (scsi_debug_dsense) { 19731da177e4SLinus Torvalds sbuff[0] = 0x72; /* descriptor, current */ 19741da177e4SLinus Torvalds sbuff[1] = key; 19751da177e4SLinus Torvalds sbuff[2] = asc; 19761da177e4SLinus Torvalds sbuff[3] = asq; 19771da177e4SLinus Torvalds } else { 19781da177e4SLinus Torvalds sbuff[0] = 0x70; /* fixed, current */ 19791da177e4SLinus Torvalds sbuff[2] = key; 19801da177e4SLinus Torvalds sbuff[7] = 0xa; /* implies 18 byte sense buffer */ 19811da177e4SLinus Torvalds sbuff[12] = asc; 19821da177e4SLinus Torvalds sbuff[13] = asq; 19831da177e4SLinus Torvalds } 19841da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 19851da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: " 19861da177e4SLinus Torvalds "[0x%x,0x%x,0x%x]\n", key, asc, asq); 19871da177e4SLinus Torvalds } 19881da177e4SLinus Torvalds 19891da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd * SCpnt) 19901da177e4SLinus Torvalds { 19911da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 19921da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: abort\n"); 19931da177e4SLinus Torvalds ++num_aborts; 19941da177e4SLinus Torvalds stop_queued_cmnd(SCpnt); 19951da177e4SLinus Torvalds return SUCCESS; 19961da177e4SLinus Torvalds } 19971da177e4SLinus Torvalds 19981da177e4SLinus Torvalds static int scsi_debug_biosparam(struct scsi_device *sdev, 19991da177e4SLinus Torvalds struct block_device * bdev, sector_t capacity, int *info) 20001da177e4SLinus Torvalds { 20011da177e4SLinus Torvalds int res; 20021da177e4SLinus Torvalds unsigned char *buf; 20031da177e4SLinus Torvalds 20041da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 20051da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: biosparam\n"); 20061da177e4SLinus Torvalds buf = scsi_bios_ptable(bdev); 20071da177e4SLinus Torvalds if (buf) { 20081da177e4SLinus Torvalds res = scsi_partsize(buf, capacity, 20091da177e4SLinus Torvalds &info[2], &info[0], &info[1]); 20101da177e4SLinus Torvalds kfree(buf); 20111da177e4SLinus Torvalds if (! res) 20121da177e4SLinus Torvalds return res; 20131da177e4SLinus Torvalds } 20141da177e4SLinus Torvalds info[0] = sdebug_heads; 20151da177e4SLinus Torvalds info[1] = sdebug_sectors_per; 20161da177e4SLinus Torvalds info[2] = sdebug_cylinders_per; 20171da177e4SLinus Torvalds return 0; 20181da177e4SLinus Torvalds } 20191da177e4SLinus Torvalds 20201da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt) 20211da177e4SLinus Torvalds { 20221da177e4SLinus Torvalds struct sdebug_dev_info * devip; 20231da177e4SLinus Torvalds 20241da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 20251da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: device_reset\n"); 20261da177e4SLinus Torvalds ++num_dev_resets; 20271da177e4SLinus Torvalds if (SCpnt) { 20281da177e4SLinus Torvalds devip = devInfoReg(SCpnt->device); 20291da177e4SLinus Torvalds if (devip) 20301da177e4SLinus Torvalds devip->reset = 1; 20311da177e4SLinus Torvalds } 20321da177e4SLinus Torvalds return SUCCESS; 20331da177e4SLinus Torvalds } 20341da177e4SLinus Torvalds 20351da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt) 20361da177e4SLinus Torvalds { 20371da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 20381da177e4SLinus Torvalds struct sdebug_dev_info * dev_info; 20391da177e4SLinus Torvalds struct scsi_device * sdp; 20401da177e4SLinus Torvalds struct Scsi_Host * hp; 20411da177e4SLinus Torvalds 20421da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 20431da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: bus_reset\n"); 20441da177e4SLinus Torvalds ++num_bus_resets; 20451da177e4SLinus Torvalds if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) { 20461da177e4SLinus Torvalds sdbg_host = *(struct sdebug_host_info **) hp->hostdata; 20471da177e4SLinus Torvalds if (sdbg_host) { 20481da177e4SLinus Torvalds list_for_each_entry(dev_info, 20491da177e4SLinus Torvalds &sdbg_host->dev_info_list, 20501da177e4SLinus Torvalds dev_list) 20511da177e4SLinus Torvalds dev_info->reset = 1; 20521da177e4SLinus Torvalds } 20531da177e4SLinus Torvalds } 20541da177e4SLinus Torvalds return SUCCESS; 20551da177e4SLinus Torvalds } 20561da177e4SLinus Torvalds 20571da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt) 20581da177e4SLinus Torvalds { 20591da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 20601da177e4SLinus Torvalds struct sdebug_dev_info * dev_info; 20611da177e4SLinus Torvalds 20621da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 20631da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: host_reset\n"); 20641da177e4SLinus Torvalds ++num_host_resets; 20651da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 20661da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 20671da177e4SLinus Torvalds list_for_each_entry(dev_info, &sdbg_host->dev_info_list, 20681da177e4SLinus Torvalds dev_list) 20691da177e4SLinus Torvalds dev_info->reset = 1; 20701da177e4SLinus Torvalds } 20711da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 20721da177e4SLinus Torvalds stop_all_queued(); 20731da177e4SLinus Torvalds return SUCCESS; 20741da177e4SLinus Torvalds } 20751da177e4SLinus Torvalds 20761da177e4SLinus Torvalds /* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */ 20771da177e4SLinus Torvalds static int stop_queued_cmnd(struct scsi_cmnd * cmnd) 20781da177e4SLinus Torvalds { 20791da177e4SLinus Torvalds unsigned long iflags; 20801da177e4SLinus Torvalds int k; 20811da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 20821da177e4SLinus Torvalds 20831da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 20841da177e4SLinus Torvalds for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 20851da177e4SLinus Torvalds sqcp = &queued_arr[k]; 20861da177e4SLinus Torvalds if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) { 20871da177e4SLinus Torvalds del_timer_sync(&sqcp->cmnd_timer); 20881da177e4SLinus Torvalds sqcp->in_use = 0; 20891da177e4SLinus Torvalds sqcp->a_cmnd = NULL; 20901da177e4SLinus Torvalds break; 20911da177e4SLinus Torvalds } 20921da177e4SLinus Torvalds } 20931da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 20941da177e4SLinus Torvalds return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0; 20951da177e4SLinus Torvalds } 20961da177e4SLinus Torvalds 20971da177e4SLinus Torvalds /* Deletes (stops) timers of all queued commands */ 20981da177e4SLinus Torvalds static void stop_all_queued(void) 20991da177e4SLinus Torvalds { 21001da177e4SLinus Torvalds unsigned long iflags; 21011da177e4SLinus Torvalds int k; 21021da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 21031da177e4SLinus Torvalds 21041da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 21051da177e4SLinus Torvalds for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 21061da177e4SLinus Torvalds sqcp = &queued_arr[k]; 21071da177e4SLinus Torvalds if (sqcp->in_use && sqcp->a_cmnd) { 21081da177e4SLinus Torvalds del_timer_sync(&sqcp->cmnd_timer); 21091da177e4SLinus Torvalds sqcp->in_use = 0; 21101da177e4SLinus Torvalds sqcp->a_cmnd = NULL; 21111da177e4SLinus Torvalds } 21121da177e4SLinus Torvalds } 21131da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 21141da177e4SLinus Torvalds } 21151da177e4SLinus Torvalds 21161da177e4SLinus Torvalds /* Initializes timers in queued array */ 21171da177e4SLinus Torvalds static void __init init_all_queued(void) 21181da177e4SLinus Torvalds { 21191da177e4SLinus Torvalds unsigned long iflags; 21201da177e4SLinus Torvalds int k; 21211da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 21221da177e4SLinus Torvalds 21231da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 21241da177e4SLinus Torvalds for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 21251da177e4SLinus Torvalds sqcp = &queued_arr[k]; 21261da177e4SLinus Torvalds init_timer(&sqcp->cmnd_timer); 21271da177e4SLinus Torvalds sqcp->in_use = 0; 21281da177e4SLinus Torvalds sqcp->a_cmnd = NULL; 21291da177e4SLinus Torvalds } 21301da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 21311da177e4SLinus Torvalds } 21321da177e4SLinus Torvalds 21331da177e4SLinus Torvalds static void __init sdebug_build_parts(unsigned char * ramp) 21341da177e4SLinus Torvalds { 21351da177e4SLinus Torvalds struct partition * pp; 21361da177e4SLinus Torvalds int starts[SDEBUG_MAX_PARTS + 2]; 21371da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 21381da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 21391da177e4SLinus Torvalds 21401da177e4SLinus Torvalds /* assume partition table already zeroed */ 21411da177e4SLinus Torvalds if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576)) 21421da177e4SLinus Torvalds return; 21431da177e4SLinus Torvalds if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) { 21441da177e4SLinus Torvalds scsi_debug_num_parts = SDEBUG_MAX_PARTS; 21451da177e4SLinus Torvalds printk(KERN_WARNING "scsi_debug:build_parts: reducing " 21461da177e4SLinus Torvalds "partitions to %d\n", SDEBUG_MAX_PARTS); 21471da177e4SLinus Torvalds } 2148c65b1445SDouglas Gilbert num_sectors = (int)sdebug_store_sectors; 21491da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 21501da177e4SLinus Torvalds / scsi_debug_num_parts; 21511da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 21521da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 21531da177e4SLinus Torvalds for (k = 1; k < scsi_debug_num_parts; ++k) 21541da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 21551da177e4SLinus Torvalds * heads_by_sects; 21561da177e4SLinus Torvalds starts[scsi_debug_num_parts] = num_sectors; 21571da177e4SLinus Torvalds starts[scsi_debug_num_parts + 1] = 0; 21581da177e4SLinus Torvalds 21591da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 21601da177e4SLinus Torvalds ramp[511] = 0xAA; 21611da177e4SLinus Torvalds pp = (struct partition *)(ramp + 0x1be); 21621da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 21631da177e4SLinus Torvalds start_sec = starts[k]; 21641da177e4SLinus Torvalds end_sec = starts[k + 1] - 1; 21651da177e4SLinus Torvalds pp->boot_ind = 0; 21661da177e4SLinus Torvalds 21671da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 21681da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 21691da177e4SLinus Torvalds / sdebug_sectors_per; 21701da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 21711da177e4SLinus Torvalds 21721da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 21731da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 21741da177e4SLinus Torvalds / sdebug_sectors_per; 21751da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 21761da177e4SLinus Torvalds 21771da177e4SLinus Torvalds pp->start_sect = start_sec; 21781da177e4SLinus Torvalds pp->nr_sects = end_sec - start_sec + 1; 21791da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 21801da177e4SLinus Torvalds } 21811da177e4SLinus Torvalds } 21821da177e4SLinus Torvalds 21831da177e4SLinus Torvalds static int schedule_resp(struct scsi_cmnd * cmnd, 21841da177e4SLinus Torvalds struct sdebug_dev_info * devip, 21851da177e4SLinus Torvalds done_funct_t done, int scsi_result, int delta_jiff) 21861da177e4SLinus Torvalds { 21871da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) { 21881da177e4SLinus Torvalds if (scsi_result) { 21891da177e4SLinus Torvalds struct scsi_device * sdp = cmnd->device; 21901da177e4SLinus Torvalds 2191c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: <%u %u %u %u> " 2192c65b1445SDouglas Gilbert "non-zero result=0x%x\n", sdp->host->host_no, 2193c65b1445SDouglas Gilbert sdp->channel, sdp->id, sdp->lun, scsi_result); 21941da177e4SLinus Torvalds } 21951da177e4SLinus Torvalds } 21961da177e4SLinus Torvalds if (cmnd && devip) { 21971da177e4SLinus Torvalds /* simulate autosense by this driver */ 21981da177e4SLinus Torvalds if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff)) 21991da177e4SLinus Torvalds memcpy(cmnd->sense_buffer, devip->sense_buff, 22001da177e4SLinus Torvalds (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ? 22011da177e4SLinus Torvalds SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE); 22021da177e4SLinus Torvalds } 22031da177e4SLinus Torvalds if (delta_jiff <= 0) { 22041da177e4SLinus Torvalds if (cmnd) 22051da177e4SLinus Torvalds cmnd->result = scsi_result; 22061da177e4SLinus Torvalds if (done) 22071da177e4SLinus Torvalds done(cmnd); 22081da177e4SLinus Torvalds return 0; 22091da177e4SLinus Torvalds } else { 22101da177e4SLinus Torvalds unsigned long iflags; 22111da177e4SLinus Torvalds int k; 22121da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp = NULL; 22131da177e4SLinus Torvalds 22141da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 22151da177e4SLinus Torvalds for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 22161da177e4SLinus Torvalds sqcp = &queued_arr[k]; 22171da177e4SLinus Torvalds if (! sqcp->in_use) 22181da177e4SLinus Torvalds break; 22191da177e4SLinus Torvalds } 22201da177e4SLinus Torvalds if (k >= SCSI_DEBUG_CANQUEUE) { 22211da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 22221da177e4SLinus Torvalds printk(KERN_WARNING "scsi_debug: can_queue exceeded\n"); 22231da177e4SLinus Torvalds return 1; /* report busy to mid level */ 22241da177e4SLinus Torvalds } 22251da177e4SLinus Torvalds sqcp->in_use = 1; 22261da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 22271da177e4SLinus Torvalds sqcp->scsi_result = scsi_result; 22281da177e4SLinus Torvalds sqcp->done_funct = done; 22291da177e4SLinus Torvalds sqcp->cmnd_timer.function = timer_intr_handler; 22301da177e4SLinus Torvalds sqcp->cmnd_timer.data = k; 22311da177e4SLinus Torvalds sqcp->cmnd_timer.expires = jiffies + delta_jiff; 22321da177e4SLinus Torvalds add_timer(&sqcp->cmnd_timer); 22331da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 22341da177e4SLinus Torvalds if (cmnd) 22351da177e4SLinus Torvalds cmnd->result = 0; 22361da177e4SLinus Torvalds return 0; 22371da177e4SLinus Torvalds } 22381da177e4SLinus Torvalds } 22391da177e4SLinus Torvalds 224023183910SDouglas Gilbert /* Note: The following macros create attribute files in the 224123183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 224223183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 224323183910SDouglas Gilbert as it can when the corresponding attribute in the 224423183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 224523183910SDouglas Gilbert */ 2246c65b1445SDouglas Gilbert module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR); 2247c65b1445SDouglas Gilbert module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR); 2248c65b1445SDouglas Gilbert module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO); 2249c65b1445SDouglas Gilbert module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR); 2250c65b1445SDouglas Gilbert module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR); 225123183910SDouglas Gilbert module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR); 2252c65b1445SDouglas Gilbert module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR); 2253c65b1445SDouglas Gilbert module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR); 2254c65b1445SDouglas Gilbert module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO); 2255c65b1445SDouglas Gilbert module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR); 2256c65b1445SDouglas Gilbert module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR); 2257c65b1445SDouglas Gilbert module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR); 2258c65b1445SDouglas Gilbert module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO); 2259c65b1445SDouglas Gilbert module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); 226023183910SDouglas Gilbert module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, 226123183910SDouglas Gilbert S_IRUGO | S_IWUSR); 22621da177e4SLinus Torvalds 22631da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 22641da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 22651da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 22661da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION); 22671da177e4SLinus Torvalds 22681da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); 22691da177e4SLinus Torvalds MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)"); 2270c65b1445SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)"); 2271c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 22721da177e4SLinus Torvalds MODULE_PARM_DESC(every_nth, "timeout every nth command(def=100)"); 227323183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 2274c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 2275c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 22761da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 2277c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 2278c65b1445SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->... (def=0)"); 22791da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 22801da177e4SLinus Torvalds MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); 2281c65b1445SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); 228223183910SDouglas Gilbert MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 22831da177e4SLinus Torvalds 22841da177e4SLinus Torvalds 22851da177e4SLinus Torvalds static char sdebug_info[256]; 22861da177e4SLinus Torvalds 22871da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp) 22881da177e4SLinus Torvalds { 22891da177e4SLinus Torvalds sprintf(sdebug_info, "scsi_debug, version %s [%s], " 22901da177e4SLinus Torvalds "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION, 22911da177e4SLinus Torvalds scsi_debug_version_date, scsi_debug_dev_size_mb, 22921da177e4SLinus Torvalds scsi_debug_opts); 22931da177e4SLinus Torvalds return sdebug_info; 22941da177e4SLinus Torvalds } 22951da177e4SLinus Torvalds 22961da177e4SLinus Torvalds /* scsi_debug_proc_info 22971da177e4SLinus Torvalds * Used if the driver currently has no own support for /proc/scsi 22981da177e4SLinus Torvalds */ 22991da177e4SLinus Torvalds static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, 23001da177e4SLinus Torvalds int length, int inout) 23011da177e4SLinus Torvalds { 23021da177e4SLinus Torvalds int len, pos, begin; 23031da177e4SLinus Torvalds int orig_length; 23041da177e4SLinus Torvalds 23051da177e4SLinus Torvalds orig_length = length; 23061da177e4SLinus Torvalds 23071da177e4SLinus Torvalds if (inout == 1) { 23081da177e4SLinus Torvalds char arr[16]; 23091da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 23101da177e4SLinus Torvalds 23111da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 23121da177e4SLinus Torvalds return -EACCES; 23131da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 23141da177e4SLinus Torvalds arr[minLen] = '\0'; 23151da177e4SLinus Torvalds if (1 != sscanf(arr, "%d", &pos)) 23161da177e4SLinus Torvalds return -EINVAL; 23171da177e4SLinus Torvalds scsi_debug_opts = pos; 23181da177e4SLinus Torvalds if (scsi_debug_every_nth != 0) 23191da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 23201da177e4SLinus Torvalds return length; 23211da177e4SLinus Torvalds } 23221da177e4SLinus Torvalds begin = 0; 23231da177e4SLinus Torvalds pos = len = sprintf(buffer, "scsi_debug adapter driver, version " 23241da177e4SLinus Torvalds "%s [%s]\n" 23251da177e4SLinus Torvalds "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, " 23261da177e4SLinus Torvalds "every_nth=%d(curr:%d)\n" 23271da177e4SLinus Torvalds "delay=%d, max_luns=%d, scsi_level=%d\n" 23281da177e4SLinus Torvalds "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n" 23291da177e4SLinus Torvalds "number of aborts=%d, device_reset=%d, bus_resets=%d, " 23301da177e4SLinus Torvalds "host_resets=%d\n", 23311da177e4SLinus Torvalds SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts, 23321da177e4SLinus Torvalds scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth, 23331da177e4SLinus Torvalds scsi_debug_cmnd_count, scsi_debug_delay, 23341da177e4SLinus Torvalds scsi_debug_max_luns, scsi_debug_scsi_level, 23351da177e4SLinus Torvalds SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, 23361da177e4SLinus Torvalds num_aborts, num_dev_resets, num_bus_resets, num_host_resets); 23371da177e4SLinus Torvalds if (pos < offset) { 23381da177e4SLinus Torvalds len = 0; 23391da177e4SLinus Torvalds begin = pos; 23401da177e4SLinus Torvalds } 23411da177e4SLinus Torvalds *start = buffer + (offset - begin); /* Start of wanted data */ 23421da177e4SLinus Torvalds len -= (offset - begin); 23431da177e4SLinus Torvalds if (len > length) 23441da177e4SLinus Torvalds len = length; 23451da177e4SLinus Torvalds return len; 23461da177e4SLinus Torvalds } 23471da177e4SLinus Torvalds 23481da177e4SLinus Torvalds static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf) 23491da177e4SLinus Torvalds { 23501da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay); 23511da177e4SLinus Torvalds } 23521da177e4SLinus Torvalds 23531da177e4SLinus Torvalds static ssize_t sdebug_delay_store(struct device_driver * ddp, 23541da177e4SLinus Torvalds const char * buf, size_t count) 23551da177e4SLinus Torvalds { 23561da177e4SLinus Torvalds int delay; 23571da177e4SLinus Torvalds char work[20]; 23581da177e4SLinus Torvalds 23591da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 23601da177e4SLinus Torvalds if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) { 23611da177e4SLinus Torvalds scsi_debug_delay = delay; 23621da177e4SLinus Torvalds return count; 23631da177e4SLinus Torvalds } 23641da177e4SLinus Torvalds } 23651da177e4SLinus Torvalds return -EINVAL; 23661da177e4SLinus Torvalds } 23671da177e4SLinus Torvalds DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show, 23681da177e4SLinus Torvalds sdebug_delay_store); 23691da177e4SLinus Torvalds 23701da177e4SLinus Torvalds static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf) 23711da177e4SLinus Torvalds { 23721da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts); 23731da177e4SLinus Torvalds } 23741da177e4SLinus Torvalds 23751da177e4SLinus Torvalds static ssize_t sdebug_opts_store(struct device_driver * ddp, 23761da177e4SLinus Torvalds const char * buf, size_t count) 23771da177e4SLinus Torvalds { 23781da177e4SLinus Torvalds int opts; 23791da177e4SLinus Torvalds char work[20]; 23801da177e4SLinus Torvalds 23811da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 23821da177e4SLinus Torvalds if (0 == strnicmp(work,"0x", 2)) { 23831da177e4SLinus Torvalds if (1 == sscanf(&work[2], "%x", &opts)) 23841da177e4SLinus Torvalds goto opts_done; 23851da177e4SLinus Torvalds } else { 23861da177e4SLinus Torvalds if (1 == sscanf(work, "%d", &opts)) 23871da177e4SLinus Torvalds goto opts_done; 23881da177e4SLinus Torvalds } 23891da177e4SLinus Torvalds } 23901da177e4SLinus Torvalds return -EINVAL; 23911da177e4SLinus Torvalds opts_done: 23921da177e4SLinus Torvalds scsi_debug_opts = opts; 23931da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 23941da177e4SLinus Torvalds return count; 23951da177e4SLinus Torvalds } 23961da177e4SLinus Torvalds DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show, 23971da177e4SLinus Torvalds sdebug_opts_store); 23981da177e4SLinus Torvalds 23991da177e4SLinus Torvalds static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf) 24001da177e4SLinus Torvalds { 24011da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype); 24021da177e4SLinus Torvalds } 24031da177e4SLinus Torvalds static ssize_t sdebug_ptype_store(struct device_driver * ddp, 24041da177e4SLinus Torvalds const char * buf, size_t count) 24051da177e4SLinus Torvalds { 24061da177e4SLinus Torvalds int n; 24071da177e4SLinus Torvalds 24081da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 24091da177e4SLinus Torvalds scsi_debug_ptype = n; 24101da177e4SLinus Torvalds return count; 24111da177e4SLinus Torvalds } 24121da177e4SLinus Torvalds return -EINVAL; 24131da177e4SLinus Torvalds } 24141da177e4SLinus Torvalds DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store); 24151da177e4SLinus Torvalds 24161da177e4SLinus Torvalds static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf) 24171da177e4SLinus Torvalds { 24181da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense); 24191da177e4SLinus Torvalds } 24201da177e4SLinus Torvalds static ssize_t sdebug_dsense_store(struct device_driver * ddp, 24211da177e4SLinus Torvalds const char * buf, size_t count) 24221da177e4SLinus Torvalds { 24231da177e4SLinus Torvalds int n; 24241da177e4SLinus Torvalds 24251da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 24261da177e4SLinus Torvalds scsi_debug_dsense = n; 24271da177e4SLinus Torvalds return count; 24281da177e4SLinus Torvalds } 24291da177e4SLinus Torvalds return -EINVAL; 24301da177e4SLinus Torvalds } 24311da177e4SLinus Torvalds DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show, 24321da177e4SLinus Torvalds sdebug_dsense_store); 24331da177e4SLinus Torvalds 243423183910SDouglas Gilbert static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf) 243523183910SDouglas Gilbert { 243623183910SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw); 243723183910SDouglas Gilbert } 243823183910SDouglas Gilbert static ssize_t sdebug_fake_rw_store(struct device_driver * ddp, 243923183910SDouglas Gilbert const char * buf, size_t count) 244023183910SDouglas Gilbert { 244123183910SDouglas Gilbert int n; 244223183910SDouglas Gilbert 244323183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 244423183910SDouglas Gilbert scsi_debug_fake_rw = n; 244523183910SDouglas Gilbert return count; 244623183910SDouglas Gilbert } 244723183910SDouglas Gilbert return -EINVAL; 244823183910SDouglas Gilbert } 244923183910SDouglas Gilbert DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show, 245023183910SDouglas Gilbert sdebug_fake_rw_store); 245123183910SDouglas Gilbert 2452c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf) 2453c65b1445SDouglas Gilbert { 2454c65b1445SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0); 2455c65b1445SDouglas Gilbert } 2456c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp, 2457c65b1445SDouglas Gilbert const char * buf, size_t count) 2458c65b1445SDouglas Gilbert { 2459c65b1445SDouglas Gilbert int n; 2460c65b1445SDouglas Gilbert 2461c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 2462c65b1445SDouglas Gilbert scsi_debug_no_lun_0 = n; 2463c65b1445SDouglas Gilbert return count; 2464c65b1445SDouglas Gilbert } 2465c65b1445SDouglas Gilbert return -EINVAL; 2466c65b1445SDouglas Gilbert } 2467c65b1445SDouglas Gilbert DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show, 2468c65b1445SDouglas Gilbert sdebug_no_lun_0_store); 2469c65b1445SDouglas Gilbert 24701da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf) 24711da177e4SLinus Torvalds { 24721da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts); 24731da177e4SLinus Torvalds } 24741da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_store(struct device_driver * ddp, 24751da177e4SLinus Torvalds const char * buf, size_t count) 24761da177e4SLinus Torvalds { 24771da177e4SLinus Torvalds int n; 24781da177e4SLinus Torvalds 24791da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 24801da177e4SLinus Torvalds scsi_debug_num_tgts = n; 24811da177e4SLinus Torvalds sdebug_max_tgts_luns(); 24821da177e4SLinus Torvalds return count; 24831da177e4SLinus Torvalds } 24841da177e4SLinus Torvalds return -EINVAL; 24851da177e4SLinus Torvalds } 24861da177e4SLinus Torvalds DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show, 24871da177e4SLinus Torvalds sdebug_num_tgts_store); 24881da177e4SLinus Torvalds 24891da177e4SLinus Torvalds static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf) 24901da177e4SLinus Torvalds { 24911da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb); 24921da177e4SLinus Torvalds } 24931da177e4SLinus Torvalds DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL); 24941da177e4SLinus Torvalds 24951da177e4SLinus Torvalds static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf) 24961da177e4SLinus Torvalds { 24971da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts); 24981da177e4SLinus Torvalds } 24991da177e4SLinus Torvalds DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL); 25001da177e4SLinus Torvalds 25011da177e4SLinus Torvalds static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf) 25021da177e4SLinus Torvalds { 25031da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth); 25041da177e4SLinus Torvalds } 25051da177e4SLinus Torvalds static ssize_t sdebug_every_nth_store(struct device_driver * ddp, 25061da177e4SLinus Torvalds const char * buf, size_t count) 25071da177e4SLinus Torvalds { 25081da177e4SLinus Torvalds int nth; 25091da177e4SLinus Torvalds 25101da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { 25111da177e4SLinus Torvalds scsi_debug_every_nth = nth; 25121da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 25131da177e4SLinus Torvalds return count; 25141da177e4SLinus Torvalds } 25151da177e4SLinus Torvalds return -EINVAL; 25161da177e4SLinus Torvalds } 25171da177e4SLinus Torvalds DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show, 25181da177e4SLinus Torvalds sdebug_every_nth_store); 25191da177e4SLinus Torvalds 25201da177e4SLinus Torvalds static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf) 25211da177e4SLinus Torvalds { 25221da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns); 25231da177e4SLinus Torvalds } 25241da177e4SLinus Torvalds static ssize_t sdebug_max_luns_store(struct device_driver * ddp, 25251da177e4SLinus Torvalds const char * buf, size_t count) 25261da177e4SLinus Torvalds { 25271da177e4SLinus Torvalds int n; 25281da177e4SLinus Torvalds 25291da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 25301da177e4SLinus Torvalds scsi_debug_max_luns = n; 25311da177e4SLinus Torvalds sdebug_max_tgts_luns(); 25321da177e4SLinus Torvalds return count; 25331da177e4SLinus Torvalds } 25341da177e4SLinus Torvalds return -EINVAL; 25351da177e4SLinus Torvalds } 25361da177e4SLinus Torvalds DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show, 25371da177e4SLinus Torvalds sdebug_max_luns_store); 25381da177e4SLinus Torvalds 25391da177e4SLinus Torvalds static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf) 25401da177e4SLinus Torvalds { 25411da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level); 25421da177e4SLinus Torvalds } 25431da177e4SLinus Torvalds DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL); 25441da177e4SLinus Torvalds 2545c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf) 2546c65b1445SDouglas Gilbert { 2547c65b1445SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb); 2548c65b1445SDouglas Gilbert } 2549c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp, 2550c65b1445SDouglas Gilbert const char * buf, size_t count) 2551c65b1445SDouglas Gilbert { 2552c65b1445SDouglas Gilbert int n; 2553c65b1445SDouglas Gilbert 2554c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 2555c65b1445SDouglas Gilbert scsi_debug_virtual_gb = n; 2556c65b1445SDouglas Gilbert if (scsi_debug_virtual_gb > 0) { 2557c65b1445SDouglas Gilbert sdebug_capacity = 2048 * 1024; 2558c65b1445SDouglas Gilbert sdebug_capacity *= scsi_debug_virtual_gb; 2559c65b1445SDouglas Gilbert } else 2560c65b1445SDouglas Gilbert sdebug_capacity = sdebug_store_sectors; 2561c65b1445SDouglas Gilbert return count; 2562c65b1445SDouglas Gilbert } 2563c65b1445SDouglas Gilbert return -EINVAL; 2564c65b1445SDouglas Gilbert } 2565c65b1445SDouglas Gilbert DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show, 2566c65b1445SDouglas Gilbert sdebug_virtual_gb_store); 2567c65b1445SDouglas Gilbert 25681da177e4SLinus Torvalds static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf) 25691da177e4SLinus Torvalds { 25701da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host); 25711da177e4SLinus Torvalds } 25721da177e4SLinus Torvalds 25731da177e4SLinus Torvalds static ssize_t sdebug_add_host_store(struct device_driver * ddp, 25741da177e4SLinus Torvalds const char * buf, size_t count) 25751da177e4SLinus Torvalds { 25761da177e4SLinus Torvalds int delta_hosts; 25771da177e4SLinus Torvalds char work[20]; 25781da177e4SLinus Torvalds 25791da177e4SLinus Torvalds if (1 != sscanf(buf, "%10s", work)) 25801da177e4SLinus Torvalds return -EINVAL; 25811da177e4SLinus Torvalds { /* temporary hack around sscanf() problem with -ve nums */ 25821da177e4SLinus Torvalds int neg = 0; 25831da177e4SLinus Torvalds 25841da177e4SLinus Torvalds if ('-' == *work) 25851da177e4SLinus Torvalds neg = 1; 25861da177e4SLinus Torvalds if (1 != sscanf(work + neg, "%d", &delta_hosts)) 25871da177e4SLinus Torvalds return -EINVAL; 25881da177e4SLinus Torvalds if (neg) 25891da177e4SLinus Torvalds delta_hosts = -delta_hosts; 25901da177e4SLinus Torvalds } 25911da177e4SLinus Torvalds if (delta_hosts > 0) { 25921da177e4SLinus Torvalds do { 25931da177e4SLinus Torvalds sdebug_add_adapter(); 25941da177e4SLinus Torvalds } while (--delta_hosts); 25951da177e4SLinus Torvalds } else if (delta_hosts < 0) { 25961da177e4SLinus Torvalds do { 25971da177e4SLinus Torvalds sdebug_remove_adapter(); 25981da177e4SLinus Torvalds } while (++delta_hosts); 25991da177e4SLinus Torvalds } 26001da177e4SLinus Torvalds return count; 26011da177e4SLinus Torvalds } 26021da177e4SLinus Torvalds DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, 26031da177e4SLinus Torvalds sdebug_add_host_store); 26041da177e4SLinus Torvalds 260523183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp, 260623183910SDouglas Gilbert char * buf) 260723183910SDouglas Gilbert { 260823183910SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno); 260923183910SDouglas Gilbert } 261023183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp, 261123183910SDouglas Gilbert const char * buf, size_t count) 261223183910SDouglas Gilbert { 261323183910SDouglas Gilbert int n; 261423183910SDouglas Gilbert 261523183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 261623183910SDouglas Gilbert scsi_debug_vpd_use_hostno = n; 261723183910SDouglas Gilbert return count; 261823183910SDouglas Gilbert } 261923183910SDouglas Gilbert return -EINVAL; 262023183910SDouglas Gilbert } 262123183910SDouglas Gilbert DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show, 262223183910SDouglas Gilbert sdebug_vpd_use_hostno_store); 262323183910SDouglas Gilbert 262423183910SDouglas Gilbert /* Note: The following function creates attribute files in the 262523183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 262623183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 262723183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 262823183910SDouglas Gilbert is changed. For example see: sdebug_add_host_store() above. 262923183910SDouglas Gilbert */ 26306ecaff7fSRandy Dunlap static int do_create_driverfs_files(void) 26311da177e4SLinus Torvalds { 26326ecaff7fSRandy Dunlap int ret; 26336ecaff7fSRandy Dunlap 26346ecaff7fSRandy Dunlap ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host); 26356ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay); 26366ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); 26376ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense); 26386ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth); 263923183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw); 26406ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns); 264123183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0); 26426ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts); 264323183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); 26446ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype); 26456ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts); 26466ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); 264723183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); 264823183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); 26496ecaff7fSRandy Dunlap return ret; 26501da177e4SLinus Torvalds } 26511da177e4SLinus Torvalds 26521da177e4SLinus Torvalds static void do_remove_driverfs_files(void) 26531da177e4SLinus Torvalds { 265423183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); 265523183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); 26561da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); 26571da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts); 26581da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype); 26591da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); 266023183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts); 266123183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0); 26621da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns); 266323183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw); 26641da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth); 26651da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense); 26661da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); 26671da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay); 26681da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host); 26691da177e4SLinus Torvalds } 26701da177e4SLinus Torvalds 26711da177e4SLinus Torvalds static int __init scsi_debug_init(void) 26721da177e4SLinus Torvalds { 2673c65b1445SDouglas Gilbert unsigned int sz; 26741da177e4SLinus Torvalds int host_to_add; 26751da177e4SLinus Torvalds int k; 26766ecaff7fSRandy Dunlap int ret; 26771da177e4SLinus Torvalds 26781da177e4SLinus Torvalds if (scsi_debug_dev_size_mb < 1) 26791da177e4SLinus Torvalds scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 2680c65b1445SDouglas Gilbert sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576; 2681c65b1445SDouglas Gilbert sdebug_store_sectors = sdebug_store_size / SECT_SIZE; 2682c65b1445SDouglas Gilbert if (scsi_debug_virtual_gb > 0) { 2683c65b1445SDouglas Gilbert sdebug_capacity = 2048 * 1024; 2684c65b1445SDouglas Gilbert sdebug_capacity *= scsi_debug_virtual_gb; 2685c65b1445SDouglas Gilbert } else 2686c65b1445SDouglas Gilbert sdebug_capacity = sdebug_store_sectors; 26871da177e4SLinus Torvalds 26881da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 26891da177e4SLinus Torvalds sdebug_heads = 8; 26901da177e4SLinus Torvalds sdebug_sectors_per = 32; 26911da177e4SLinus Torvalds if (scsi_debug_dev_size_mb >= 16) 26921da177e4SLinus Torvalds sdebug_heads = 32; 26931da177e4SLinus Torvalds else if (scsi_debug_dev_size_mb >= 256) 26941da177e4SLinus Torvalds sdebug_heads = 64; 26951da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 26961da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 26971da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 26981da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 26991da177e4SLinus Torvalds sdebug_heads = 255; 27001da177e4SLinus Torvalds sdebug_sectors_per = 63; 27011da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 27021da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 27031da177e4SLinus Torvalds } 27041da177e4SLinus Torvalds 27051da177e4SLinus Torvalds sz = sdebug_store_size; 27061da177e4SLinus Torvalds fake_storep = vmalloc(sz); 27071da177e4SLinus Torvalds if (NULL == fake_storep) { 27081da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug_init: out of memory, 1\n"); 27091da177e4SLinus Torvalds return -ENOMEM; 27101da177e4SLinus Torvalds } 27111da177e4SLinus Torvalds memset(fake_storep, 0, sz); 27121da177e4SLinus Torvalds if (scsi_debug_num_parts > 0) 27131da177e4SLinus Torvalds sdebug_build_parts(fake_storep); 27141da177e4SLinus Torvalds 27156ecaff7fSRandy Dunlap ret = device_register(&pseudo_primary); 27166ecaff7fSRandy Dunlap if (ret < 0) { 27176ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: device_register error: %d\n", 27186ecaff7fSRandy Dunlap ret); 27196ecaff7fSRandy Dunlap goto free_vm; 27206ecaff7fSRandy Dunlap } 27216ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 27226ecaff7fSRandy Dunlap if (ret < 0) { 27236ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: bus_register error: %d\n", 27246ecaff7fSRandy Dunlap ret); 27256ecaff7fSRandy Dunlap goto dev_unreg; 27266ecaff7fSRandy Dunlap } 27276ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 27286ecaff7fSRandy Dunlap if (ret < 0) { 27296ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: driver_register error: %d\n", 27306ecaff7fSRandy Dunlap ret); 27316ecaff7fSRandy Dunlap goto bus_unreg; 27326ecaff7fSRandy Dunlap } 27336ecaff7fSRandy Dunlap ret = do_create_driverfs_files(); 27346ecaff7fSRandy Dunlap if (ret < 0) { 27356ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n", 27366ecaff7fSRandy Dunlap ret); 27376ecaff7fSRandy Dunlap goto del_files; 27386ecaff7fSRandy Dunlap } 27391da177e4SLinus Torvalds 27406ecaff7fSRandy Dunlap init_all_queued(); 27411da177e4SLinus Torvalds 27421da177e4SLinus Torvalds sdebug_driver_template.proc_name = (char *)sdebug_proc_name; 27431da177e4SLinus Torvalds 27441da177e4SLinus Torvalds host_to_add = scsi_debug_add_host; 27451da177e4SLinus Torvalds scsi_debug_add_host = 0; 27461da177e4SLinus Torvalds 27471da177e4SLinus Torvalds for (k = 0; k < host_to_add; k++) { 27481da177e4SLinus Torvalds if (sdebug_add_adapter()) { 27491da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug_init: " 27501da177e4SLinus Torvalds "sdebug_add_adapter failed k=%d\n", k); 27511da177e4SLinus Torvalds break; 27521da177e4SLinus Torvalds } 27531da177e4SLinus Torvalds } 27541da177e4SLinus Torvalds 27551da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { 27561da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug_init: built %d host(s)\n", 27571da177e4SLinus Torvalds scsi_debug_add_host); 27581da177e4SLinus Torvalds } 27591da177e4SLinus Torvalds return 0; 27606ecaff7fSRandy Dunlap 27616ecaff7fSRandy Dunlap del_files: 27626ecaff7fSRandy Dunlap do_remove_driverfs_files(); 27636ecaff7fSRandy Dunlap driver_unregister(&sdebug_driverfs_driver); 27646ecaff7fSRandy Dunlap bus_unreg: 27656ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 27666ecaff7fSRandy Dunlap dev_unreg: 27676ecaff7fSRandy Dunlap device_unregister(&pseudo_primary); 27686ecaff7fSRandy Dunlap free_vm: 27696ecaff7fSRandy Dunlap vfree(fake_storep); 27706ecaff7fSRandy Dunlap 27716ecaff7fSRandy Dunlap return ret; 27721da177e4SLinus Torvalds } 27731da177e4SLinus Torvalds 27741da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 27751da177e4SLinus Torvalds { 27761da177e4SLinus Torvalds int k = scsi_debug_add_host; 27771da177e4SLinus Torvalds 27781da177e4SLinus Torvalds stop_all_queued(); 27791da177e4SLinus Torvalds for (; k; k--) 27801da177e4SLinus Torvalds sdebug_remove_adapter(); 27811da177e4SLinus Torvalds do_remove_driverfs_files(); 27821da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 27831da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 27841da177e4SLinus Torvalds device_unregister(&pseudo_primary); 27851da177e4SLinus Torvalds 27861da177e4SLinus Torvalds vfree(fake_storep); 27871da177e4SLinus Torvalds } 27881da177e4SLinus Torvalds 27891da177e4SLinus Torvalds device_initcall(scsi_debug_init); 27901da177e4SLinus Torvalds module_exit(scsi_debug_exit); 27911da177e4SLinus Torvalds 279252c1da39SAdrian Bunk static void pseudo_0_release(struct device * dev) 27931da177e4SLinus Torvalds { 27941da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 27951da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n"); 27961da177e4SLinus Torvalds } 27971da177e4SLinus Torvalds 27981da177e4SLinus Torvalds static struct device pseudo_primary = { 27991da177e4SLinus Torvalds .bus_id = "pseudo_0", 28001da177e4SLinus Torvalds .release = pseudo_0_release, 28011da177e4SLinus Torvalds }; 28021da177e4SLinus Torvalds 28031da177e4SLinus Torvalds static int pseudo_lld_bus_match(struct device *dev, 28041da177e4SLinus Torvalds struct device_driver *dev_driver) 28051da177e4SLinus Torvalds { 28061da177e4SLinus Torvalds return 1; 28071da177e4SLinus Torvalds } 28081da177e4SLinus Torvalds 28091da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus = { 28101da177e4SLinus Torvalds .name = "pseudo", 28111da177e4SLinus Torvalds .match = pseudo_lld_bus_match, 2812bbbe3a41SRussell King .probe = sdebug_driver_probe, 2813bbbe3a41SRussell King .remove = sdebug_driver_remove, 28141da177e4SLinus Torvalds }; 28151da177e4SLinus Torvalds 28161da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev) 28171da177e4SLinus Torvalds { 28181da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 28191da177e4SLinus Torvalds 28201da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 28211da177e4SLinus Torvalds kfree(sdbg_host); 28221da177e4SLinus Torvalds } 28231da177e4SLinus Torvalds 28241da177e4SLinus Torvalds static int sdebug_add_adapter(void) 28251da177e4SLinus Torvalds { 28261da177e4SLinus Torvalds int k, devs_per_host; 28271da177e4SLinus Torvalds int error = 0; 28281da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 28291da177e4SLinus Torvalds struct sdebug_dev_info *sdbg_devinfo; 28301da177e4SLinus Torvalds struct list_head *lh, *lh_sf; 28311da177e4SLinus Torvalds 283224669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); 28331da177e4SLinus Torvalds 28341da177e4SLinus Torvalds if (NULL == sdbg_host) { 28351da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 28361da177e4SLinus Torvalds __FUNCTION__, __LINE__); 28371da177e4SLinus Torvalds return -ENOMEM; 28381da177e4SLinus Torvalds } 28391da177e4SLinus Torvalds 28401da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 28411da177e4SLinus Torvalds 28421da177e4SLinus Torvalds devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns; 28431da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 284424669f75SJes Sorensen sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo),GFP_KERNEL); 28451da177e4SLinus Torvalds if (NULL == sdbg_devinfo) { 28461da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 28471da177e4SLinus Torvalds __FUNCTION__, __LINE__); 28481da177e4SLinus Torvalds error = -ENOMEM; 28491da177e4SLinus Torvalds goto clean; 28501da177e4SLinus Torvalds } 28511da177e4SLinus Torvalds sdbg_devinfo->sdbg_host = sdbg_host; 28521da177e4SLinus Torvalds list_add_tail(&sdbg_devinfo->dev_list, 28531da177e4SLinus Torvalds &sdbg_host->dev_info_list); 28541da177e4SLinus Torvalds } 28551da177e4SLinus Torvalds 28561da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 28571da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 28581da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 28591da177e4SLinus Torvalds 28601da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 28611da177e4SLinus Torvalds sdbg_host->dev.parent = &pseudo_primary; 28621da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 28631da177e4SLinus Torvalds sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host); 28641da177e4SLinus Torvalds 28651da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 28661da177e4SLinus Torvalds 28671da177e4SLinus Torvalds if (error) 28681da177e4SLinus Torvalds goto clean; 28691da177e4SLinus Torvalds 28701da177e4SLinus Torvalds ++scsi_debug_add_host; 28711da177e4SLinus Torvalds return error; 28721da177e4SLinus Torvalds 28731da177e4SLinus Torvalds clean: 28741da177e4SLinus Torvalds list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) { 28751da177e4SLinus Torvalds sdbg_devinfo = list_entry(lh, struct sdebug_dev_info, 28761da177e4SLinus Torvalds dev_list); 28771da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 28781da177e4SLinus Torvalds kfree(sdbg_devinfo); 28791da177e4SLinus Torvalds } 28801da177e4SLinus Torvalds 28811da177e4SLinus Torvalds kfree(sdbg_host); 28821da177e4SLinus Torvalds return error; 28831da177e4SLinus Torvalds } 28841da177e4SLinus Torvalds 28851da177e4SLinus Torvalds static void sdebug_remove_adapter(void) 28861da177e4SLinus Torvalds { 28871da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host = NULL; 28881da177e4SLinus Torvalds 28891da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 28901da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 28911da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 28921da177e4SLinus Torvalds struct sdebug_host_info, host_list); 28931da177e4SLinus Torvalds list_del(&sdbg_host->host_list); 28941da177e4SLinus Torvalds } 28951da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 28961da177e4SLinus Torvalds 28971da177e4SLinus Torvalds if (!sdbg_host) 28981da177e4SLinus Torvalds return; 28991da177e4SLinus Torvalds 29001da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 29011da177e4SLinus Torvalds --scsi_debug_add_host; 29021da177e4SLinus Torvalds } 29031da177e4SLinus Torvalds 29041da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev) 29051da177e4SLinus Torvalds { 29061da177e4SLinus Torvalds int error = 0; 29071da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 29081da177e4SLinus Torvalds struct Scsi_Host *hpnt; 29091da177e4SLinus Torvalds 29101da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 29111da177e4SLinus Torvalds 29121da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 29131da177e4SLinus Torvalds if (NULL == hpnt) { 29141da177e4SLinus Torvalds printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__); 29151da177e4SLinus Torvalds error = -ENODEV; 29161da177e4SLinus Torvalds return error; 29171da177e4SLinus Torvalds } 29181da177e4SLinus Torvalds 29191da177e4SLinus Torvalds sdbg_host->shost = hpnt; 29201da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 29211da177e4SLinus Torvalds if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id)) 29221da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts + 1; 29231da177e4SLinus Torvalds else 29241da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts; 2925c65b1445SDouglas Gilbert hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */ 29261da177e4SLinus Torvalds 29271da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 29281da177e4SLinus Torvalds if (error) { 29291da177e4SLinus Torvalds printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__); 29301da177e4SLinus Torvalds error = -ENODEV; 29311da177e4SLinus Torvalds scsi_host_put(hpnt); 29321da177e4SLinus Torvalds } else 29331da177e4SLinus Torvalds scsi_scan_host(hpnt); 29341da177e4SLinus Torvalds 29351da177e4SLinus Torvalds 29361da177e4SLinus Torvalds return error; 29371da177e4SLinus Torvalds } 29381da177e4SLinus Torvalds 29391da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev) 29401da177e4SLinus Torvalds { 29411da177e4SLinus Torvalds struct list_head *lh, *lh_sf; 29421da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 29431da177e4SLinus Torvalds struct sdebug_dev_info *sdbg_devinfo; 29441da177e4SLinus Torvalds 29451da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 29461da177e4SLinus Torvalds 29471da177e4SLinus Torvalds if (!sdbg_host) { 29481da177e4SLinus Torvalds printk(KERN_ERR "%s: Unable to locate host info\n", 29491da177e4SLinus Torvalds __FUNCTION__); 29501da177e4SLinus Torvalds return -ENODEV; 29511da177e4SLinus Torvalds } 29521da177e4SLinus Torvalds 29531da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 29541da177e4SLinus Torvalds 29551da177e4SLinus Torvalds list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) { 29561da177e4SLinus Torvalds sdbg_devinfo = list_entry(lh, struct sdebug_dev_info, 29571da177e4SLinus Torvalds dev_list); 29581da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 29591da177e4SLinus Torvalds kfree(sdbg_devinfo); 29601da177e4SLinus Torvalds } 29611da177e4SLinus Torvalds 29621da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 29631da177e4SLinus Torvalds return 0; 29641da177e4SLinus Torvalds } 29651da177e4SLinus Torvalds 29661da177e4SLinus Torvalds static void sdebug_max_tgts_luns(void) 29671da177e4SLinus Torvalds { 29681da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 29691da177e4SLinus Torvalds struct Scsi_Host *hpnt; 29701da177e4SLinus Torvalds 29711da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 29721da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 29731da177e4SLinus Torvalds hpnt = sdbg_host->shost; 29741da177e4SLinus Torvalds if ((hpnt->this_id >= 0) && 29751da177e4SLinus Torvalds (scsi_debug_num_tgts > hpnt->this_id)) 29761da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts + 1; 29771da177e4SLinus Torvalds else 29781da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts; 2979c65b1445SDouglas Gilbert hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */ 29801da177e4SLinus Torvalds } 29811da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 29821da177e4SLinus Torvalds } 2983